Aider-AI/aider · error · ValueError

Bad/missing filename. The filename must be alone on the line

Error message

Bad/missing filename. The filename must be alone on the line before the opening fence {fence[0]}

What it means

Raised by the SEARCH/REPLACE parser in editblock_coder while iterating fenced blocks: the parser hit an opening fence (matched head_pattern), looked back up to 3 lines for a filename (find_filename), found none, and there was no current_filename carried over from a previous block. The filename must sit alone on the line directly before the opening fence (e.g. ```python).

Source

Thrown at aider/coders/editblock_coder.py:500

                i += 1  # Skip the closing ```

            yield None, "".join(shell_content)
            continue

        # Check for SEARCH/REPLACE blocks
        if head_pattern.match(line.strip()):
            try:
                # if next line after HEAD exists and is DIVIDER, it's a new file
                if i + 1 < len(lines) and divider_pattern.match(lines[i + 1].strip()):
                    filename = find_filename(lines[max(0, i - 3) : i], fence, None)
                else:
                    filename = find_filename(lines[max(0, i - 3) : i], fence, valid_fnames)

                if not filename:
                    if current_filename:
                        filename = current_filename
                    else:
                        raise ValueError(missing_filename_err.format(fence=fence))

                current_filename = filename

                original_text = []
                i += 1
                while i < len(lines) and not divider_pattern.match(lines[i].strip()):
                    original_text.append(lines[i])
                    i += 1

                if i >= len(lines) or not divider_pattern.match(lines[i].strip()):
                    raise ValueError(f"Expected `{DIVIDER_ERR}`")

                updated_text = []
                i += 1
                while i < len(lines) and not (
                    updated_pattern.match(lines[i].strip())
                    or divider_pattern.match(lines[i].strip())
                ):

View on GitHub (pinned to 5dc9490bb3)

Solutions

  1. Ensure every SEARCH/REPLACE block is preceded by the bare filename on its own line (foo.py) immediately before the fence.
  2. If driving the coder programmatically, pass valid_fnames for files already in the chat so the parser can pick the filename from context.
  3. Send the error text back to the LLM — aider's retry loop asks the model to re-emit properly labeled blocks.
  4. Add the target file to the chat first (/add foo.py) so current_filename/valid_fnames resolution can succeed.

Example fix

# before (LLM reply)
Here is the fix:
```
<<<<<<< SEARCH
old line
=======
new line
>>>>>>> REPLACE
```

# after
Here is the fix:
foo.py
```
<<<<<<< SEARCH
old line
=======
new line
>>>>>>> REPLACE
```
Defensive patterns

Strategy: validation

Validate before calling

import re
FENCE = re.compile(r"^```\w*$")

def blocks_have_filenames(reply: str, known_files: set[str]) -> list[str]:
    missing = []
    lines = reply.splitlines()
    for i, line in enumerate(lines):
        if FENCE.match(line.strip()):
            before = [l for l in lines[max(0, i - 3):i] if l.strip()]
            if not any(l.strip() in known_files for l in before):
                missing.append(line)
    return missing  # non-empty → expect the parser error; fix the reply first

Try / catch

try:
    edits = list(parse_edits_or_raise(reply))
except ValueError as e:
    if "filename must be alone on the line" in str(e):
        reply = ask_model_to_relabel_blocks(str(e))  # feed back for retry
        edits = list(parse_edits_or_raise(reply))
    else:
        raise

Prevention

When it happens

Trigger: An LLM reply containing a SEARCH/REPLACE block whose preceding lines contain no recognizable path — filename omitted, embedded in prose, placed after the fence, or written with the fence on the same line. Fires on the first block of a reply (no current_filename fallback) or when filename detection fails for a later block after the previous one had no filename either.

Common situations: Models that wrap code in fences without naming the file (DeepSeek-style outputs the code comments on); filenames written as 'File: foo.py' or inside backticks with other text so find_filename's heuristics miss them; chat history where earlier blocks already consumed/lost the filename context.

Related errors


AI-assisted analysis of Aider-AI/aider@5dc9490bb3 (2026-08-15). Data as JSON: /api/errors/36616184b5f764aa. Report an issue: GitHub.