Aider-AI/aider · error · ValueError

Expected `>>>>>>> REPLACE` or `=======`

Error message

Expected `>>>>>>> REPLACE` or `=======`

What it means

Raised by the SEARCH/REPLACE parser when the REPLACE section is not properly terminated: after collecting updated_text lines, the parser expects a >>>>>>> REPLACE line (or another ======= for chained sections) and instead hits end-of-input or an unrelated line. Every REPLACE section must close with >>>>>>> REPLACE.

Source

Thrown at aider/coders/editblock_coder.py:526

                    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)

            except ValueError as e:
                processed = "".join(lines[: i + 1])
                err = e.args[0]
                raise ValueError(f"{processed}\n^^^ {err}")

        i += 1


def find_filename(lines, fence, valid_fnames):
    """
    Deepseek Coder v2 has been doing this:


     ```python
    word_count.py

View on GitHub (pinned to 5dc9490bb3)

Solutions

  1. Inspect the ^^^ context in the message to find where termination was expected.
  2. Ensure each block ends with >>>>>>> REPLACE (exactly seven '>' plus ' REPLACE').
  3. Increase output token budget if truncation is the cause.
  4. Return the error to the model for a corrected re-emit, or switch edit format.

Example fix

# before
<<<<<<< SEARCH
old
=======
new
>>>>>>> (malformed)

# after
<<<<<<< SEARCH
old
=======
new
>>>>>>> REPLACE
Defensive patterns

Strategy: validation

Validate before calling

def check_block_terminator(text: str) -> str | None:
    import re
    if not re.search(r"(?m)^>>>>>>> REPLACE$", text):
        return "missing '>>>>>>> REPLACE' terminator"
    return None

Try / catch

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

Prevention

When it happens

Trigger: A block missing the >>>>>>> REPLACE terminator, using the wrong number of '>' characters, or a reply truncated after the replacement content; also when stray text follows the replacement lines instead of the closing marker.

Common situations: Models abbreviating the closing marker; max_tokens truncation cutting the reply mid-block; hand-written edits pasted into prompts without the full marker grammar.

Related errors


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