{"record":{"id":"a7a433306c27028e","repo":"datawhalechina/hello-agents","slug":"patch-hunk-context-not-found-file-changed","errorCode":null,"errorMessage":"Patch hunk context not found; file changed?","messagePattern":"Patch hunk context not found; file changed\\?","errorType":"exception","errorClass":"PatchApplyError","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py","lineNumber":467,"sourceCode":"                continue\n            tag = l[0]\n            text = l[1:] + \"\\n\"\n            if tag == \" \":\n                before.append(text)\n                after.append(text)\n            elif tag == \"-\":\n                before.append(text)\n            elif tag == \"+\":\n                after.append(text)\n\n        if not before:\n            raise PatchApplyError(\"Update hunk has no context/removals; refusing to apply\")\n\n        idx = self._find_subsequence(current, before)\n        if idx is None:\n            context_line = next((b.strip() for b in before if b.strip()), \"\")\n            hint = f\"{rel_path}:search:'{context_line[:80]}'\"\n            raise PatchApplyError(\"Patch hunk context not found; file changed?\", recheck_targets=[hint])\n\n        return current[:idx] + after + current[idx + len(before) :]\n\n    def _find_subsequence(self, haystack: List[str], needle: List[str]) -> Optional[int]:\n        \"\"\"\n        在文件内容中查找代码块的起始位置。\n        使用简单的 O(N*M) 字符串匹配算法，在 haystack 中查找 needle 的精确匹配。\n        \n        参数:\n            haystack: 文件内容行列表\n            needle: 要查找的代码块行列表\n            \n        返回:\n            Optional[int]: 匹配的起始行索引，如果未找到则返回 None\n        \"\"\"\n        if len(needle) > len(haystack):\n            return None\n        for i in range(0, len(haystack) - len(needle) + 1):","sourceCodeStart":449,"sourceCodeEnd":485,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py#L449-L485","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nexcept PatchApplyError as e:\n    if e.recheck_targets:\n        abort()  # give up\n\n# after\nexcept PatchApplyError as e:\n    if e.recheck_targets:\n        fresh = read_file(rel_path)         # re-read current content\n        patch = regenerate_hunk(fresh)       # rebuild context lines\n        result = executor.apply(patch)       # retry once","handlingStrategy":"retry","validationCode":"current = (repo_root / rel_path).read_text().splitlines()\ncontext = [l[1:] + '\\n' for l in hunk_lines if l.startswith((' ', '-'))]\nif executor._find_subsequence(current, context) is None:\n    raise ValueError('context stale; re-read file and regenerate hunk')","typeGuard":null,"tryCatchPattern":"try:\n    executor.apply(patch_text)\nexcept PatchApplyError as e:\n    if 'context not found' in str(e):\n        fresh = read_target_files(e.recheck_targets)   # re-read current state\n        patch_text = regenerate_hunks(fresh)            # rebuild from reality\n        return executor.apply(patch_text)               # one bounded retry\n    raise","preventionTips":["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."],"tags":["patch","conflict","stale-state","apply-patch"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}