datawhalechina/hello-agents · error · PatchApplyError
Patch hunk context not found; file changed?
Error message
Patch hunk context not found; file changed?
What it means
Raised when the hunk's before/context lines cannot be found as an exact contiguous subsequence of the current file content (_find_subsequence returns None). It means the file on disk differs from what the patch author saw — concurrent edits, stale context, or whitespace mismatches. The error carries a recheck_targets hint ('file:search:\'context line\'') so an agent can re-read the file.
Source
Thrown at Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py:467
continue
tag = l[0]
text = l[1:] + "\n"
if tag == " ":
before.append(text)
after.append(text)
elif tag == "-":
before.append(text)
elif tag == "+":
after.append(text)
if not before:
raise PatchApplyError("Update hunk has no context/removals; refusing to apply")
idx = self._find_subsequence(current, before)
if idx is None:
context_line = next((b.strip() for b in before if b.strip()), "")
hint = f"{rel_path}:search:'{context_line[:80]}'"
raise PatchApplyError("Patch hunk context not found; file changed?", recheck_targets=[hint])
return current[:idx] + after + current[idx + len(before) :]
def _find_subsequence(self, haystack: List[str], needle: List[str]) -> Optional[int]:
"""
在文件内容中查找代码块的起始位置。
使用简单的 O(N*M) 字符串匹配算法,在 haystack 中查找 needle 的精确匹配。
参数:
haystack: 文件内容行列表
needle: 要查找的代码块行列表
返回:
Optional[int]: 匹配的起始行索引,如果未找到则返回 None
"""
if len(needle) > len(haystack):
return None
for i in range(0, len(haystack) - len(needle) + 1):View on GitHub (pinned to 606a07d341)
Solutions
- Re-read the target file (the recheck_targets hint gives the search string) and regenerate the hunk from current content.
- Apply pending patches to the same file serially, re-reading after each apply.
- Check for whitespace/line-ending drift; include context lines copied verbatim from the file.
Example fix
# before
except PatchApplyError as e:
if e.recheck_targets:
abort() # give up
# after
except PatchApplyError as e:
if e.recheck_targets:
fresh = read_file(rel_path) # re-read current content
patch = regenerate_hunk(fresh) # rebuild context lines
result = executor.apply(patch) # retry once Defensive patterns
Strategy: retry
Validate before calling
current = (repo_root / rel_path).read_text().splitlines()
context = [l[1:] + '\n' for l in hunk_lines if l.startswith((' ', '-'))]
if executor._find_subsequence(current, context) is None:
raise ValueError('context stale; re-read file and regenerate hunk') Try / catch
try:
executor.apply(patch_text)
except PatchApplyError as e:
if 'context not found' in str(e):
fresh = read_target_files(e.recheck_targets) # re-read current state
patch_text = regenerate_hunks(fresh) # rebuild from reality
return executor.apply(patch_text) # one bounded retry
raise Prevention
- Re-read a file before patching it again after any other write.
- Apply patches to the same file serially in one agent step.
- Use the recheck_targets hint to re-anchor context instead of failing the whole run.
- Preserve exact whitespace/indentation in context lines.
When it happens
Trigger: Applying a patch generated against an older revision; two patches to the same file applied in the wrong order; whitespace/indentation drift (tabs vs spaces) between the patch context and the file; CRLF vs LF line endings.
Common situations: Agent applies multiple sequential patches without re-reading the file between them; another process (formatter, linter, human) touched the file; patch context copied with normalized indentation.
Related errors
- Unknown op kind: {kind}
- Absolute paths are not allowed: {rel_path}
- Path escapes repo_root: {rel_path}
- Refusing to modify symlink: {rel_path}
- Disallowed file suffix for write: {target.suffix}
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/a7a433306c27028e.
Report an issue: GitHub.