datawhalechina/hello-agents · error · PatchApplyError

Unexpected patch line: {line}

Error message

Unexpected patch line: {line}

What it means

Raised by the patch parser when a line inside the patch body (between Begin and End) is not an '*** Add File: '/'*** Update File: ' (or Delete) header, not a blank line, and therefore falls through to the catch-all raise. It marks structurally malformed patch bodies the lenient parser cannot reinterpret.

Source

Thrown at Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py:339

                continue
            if line.startswith("*** Delete File: "):
                path = line[len("*** Delete File: ") :].strip()
                ops.append(("delete", path, ""))
                i += 1
                continue
            if line.startswith("*** Update File: "):
                path = line[len("*** Update File: ") :].strip()
                i += 1
                buf: List[str] = []
                while i < len(lines) - 1 and not lines[i].startswith("*** "):
                    buf.append(lines[i])
                    i += 1
                ops.append(("update", path, "\n".join(buf)))
                continue
            if line.strip() == "":
                i += 1
                continue
            raise PatchApplyError(f"Unexpected patch line: {line}")

        return ops

    def _estimate_changed_lines(self, ops: List[Tuple[str, str, str]]) -> int:
        """
        估算补丁操作的总变更行数。
        用于检查补丁大小是否超过限制。
        
        参数:
            ops: 补丁操作列表
            
        返回:
            int: 估算的总变更行数
        """
        changed = 0
        for kind, _, payload in ops:
            if kind == "add":
                # 添加文件:按行数计算

View on GitHub (pinned to 606a07d341)

Solutions

  1. Check the exact offending line reported in the message and either remove it or wrap it inside the correct section.
  2. Replace unsupported directives: express a rename as Delete+Add, or add parser support for the directive.
  3. Re-generate the patch strictly in the Add/Update(+Delete-if-supported) grammar.

Example fix

# before
*** Update File: a.py
@@ -1,2 +1,2 @@
-old
+new
*** Rename File: a.py -> b.py   <-- unexpected line

# after
*** Update File: a.py
@@
-old
+new
(and a separate Add File / Delete File pair for the rename)
Defensive patterns

Strategy: validation

Validate before calling

KNOWN = ('*** Add File: ', '*** Update File: ', '*** Delete File: ')
in_section = False
for l in patch_text.splitlines():
    s = l.strip()
    if s == '*** Begin Patch' or s == '*** End Patch':
        in_section = (s == '*** Begin Patch'); continue
    if not in_section: continue
    if l.startswith('***') and not l.startswith(('+', '-', ' ')):
        if not l.startswith(KNOWN):
            raise ValueError(f'unsupported directive: {l!r}')

Try / catch

try:
    executor.apply(patch_text)
except PatchApplyError as e:
    if 'Unexpected patch line' in str(e):
        offending = str(e).rsplit(':', 1)[-1].strip()
        patch_text = remove_line(patch_text, offending)  # or re-prompt
    raise

Prevention

When it happens

Trigger: A stray line starting with text other than the recognized sections — e.g. '*** Delete File: foo' if Delete is not handled in this parser path, diff-style '@@ -1,3 +1,4 @@' hunk headers outside an Update body, or prose/comments at top level.

Common situations: Mixing unified-dump syntax into the codestyle patch format; models emitting '*** Rename File:' or '*** Delete File:' directives the parser skips; hand-edited patches with section markers of the wrong spelling.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/2a65737f9ba56c8a. Report an issue: GitHub.