#1985·outlines

Template.from_string leaks stray blank lines/whitespace when a trailing blank line is over-indented or tab-indented

Author: BenAyedMedAlaCreated Aug 7, 2026Updated Aug 7, 2026

Describe the issue as clearly as possible:

build_template_from_string (used by Template.from_string/Template.from_file, and by Application) is meant to collapse any trailing blank line(s) in a triple-quoted template down to exactly one trailing linebreak — see the existing test_template_from_str_with_extra_linebreaks test.

That collapsing relies on two things lining up:

  1. inspect.cleandoc(content) dedenting and dropping trailing blank lines.
  2. A heuristic, content.replace(" ", "").endswith("\n\n"), that re-adds exactly one "\n" because cleandoc would otherwise swallow the intentional blank line entirely.

Both break down once the trailing blank line's whitespace isn't "plain spaces no deeper than the template's common margin":

  • cleandoc only fully empties a trailing whitespace-only line when that line's (tab-expanded) length is <= the common indentation margin of the rest of the content. If it's deeper — extra spaces, or a tab, which expands to a full tab stop — cleandoc leaves a non-empty leftover line instead of removing it.
  • The ends_with_linebreak heuristic only strips literal " " characters from the raw content before checking for "\n\n", so it misses tabs (or any other horizontal whitespace) entirely, even when cleandoc did manage to fully clean the line.

Net effect: extra blank lines and stray trailing whitespace leak straight into the string that actually gets sent to the model — silently, with no error or warning.

Steps/code to reproduce the bug:

python
from outlines import Template

# Over-indented trailing blank line (pure spaces, no tabs needed).
# Template's common margin is 4 spaces ("Hello, ...''); the trailing
# blank line has 8.
tpl = Template.from_string("""
    Hello, {{ name }}!


        """)
print(repr(tpl(name="World")))

# Tab-indented trailing blank line.
tpl2 = Template.from_string("\n    Hello, {{ name }}!\n\n\n\t")
print(repr(tpl2(name="World")))

Expected result:

'Hello, World!\n'
'Hello, World!\n'

Both should render identically to the already-correct, evenly-indented case covered by test_template_from_str_with_extra_linebreaks (a trailing blank line indented with exactly 4 spaces, matching the margin, renders as 'Hello, World!\n').

Error message:

No exception is raised; the rendered output is silently wrong:

'Hello, World!\n\n\n    '
'Hello, World!\n\n\n    '

(Two extra blank lines plus 4 stray trailing spaces, instead of a single trailing linebreak.)

Outlines/Python version information:

Reproduced against main at commit 7d068478851f7ba76cb53997673d57f77b2d6f84, Python 3.12.

Context for the issue:

Whitespace inside prompts affects tokenization and can change model behavior, so silently leaking extra blank lines/whitespace into a rendered prompt is a real correctness issue for a prompt-templating library, not just cosmetic. This is also directly adjacent to two very recent fixes in this exact function (whitespace-collapse handling and enum/anyOf rendering), so it looks like an area still being hardened.

I have a fix + regression tests ready (.rstrip() cleandoc's own output before conditionally restoring a single trailing linebreak, and broadening the blank-line detection to any horizontal whitespace rather than just literal spaces) and will open a PR shortly.