Aider-AI/aider · error · ValueError

Expected `=======`

Error message

Expected `=======`

What it means

Raised by the SEARCH/REPLACE parser when, after collecting original_text lines following the opening fence/head, it reaches end-of-input or a line that is not the ======= divider. The SEARCH section must be terminated by a line that is exactly ======= before the REPLACE content begins.

Source

Thrown at aider/coders/editblock_coder.py:511

                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())
                ):
                    updated_text.append(lines[i])
                    i += 1

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

                yield filename, "".join(original_text), "".join(updated_text)

View on GitHub (pinned to 5dc9490bb3)

Solutions

  1. Check the error's ^^^ context: it prints the processed lines up to the failure so you can see exactly where the divider is missing or malformed.
  2. Make ======= exactly seven equals signs on its own line between SEARCH and REPLACE sections.
  3. If replies are truncated mid-block, raise max_tokens / output token limits for the model.
  4. Feed the error back to the LLM to re-emit the block with correct markers, or switch to a format the model handles more reliably (udiff/patch).

Example fix

# before
foo.py
```
<<<<<<< SEARCH
old line
=====  (wrong divider)
new line
>>>>>>> REPLACE
```

# after
foo.py
```
<<<<<<< SEARCH
old line
=======
new line
>>>>>>> REPLACE
```
Defensive patterns

Strategy: validation

Validate before calling

def check_block_grammar(text: str) -> str | None:
    import re
    if not re.search(r"(?m)^=======$", text):
        return "missing '=======' divider between SEARCH and REPLACE"
    return None  # None → safe to parse

Try / catch

try:
    edits = list(parse_edits_or_raise(reply))
except ValueError as e:
    if "Expected `=======`" in str(e):
        reply = ask_model_to_fix_dividers(str(e))
        edits = list(parse_edits_or_raise(reply))
    else:
        raise

Prevention

When it happens

Trigger: A block where the model forgot the ======= divider, used the wrong number of equals signs (===== or =========), put text on the divider line, or truncated the reply before closing the SEARCH section — the while loop consumes lines until divider_pattern matches, and if it never does (i >= len(lines)) this ValueError fires.

Common situations: Models mangling the strict diff-fenced grammar (extra/missing '=' characters); replies truncated by max_tokens so the block ends mid-SEARCH; copy-pasted diffs that use unified-diff markers instead of the ======= divider.

Related errors


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