{"record":{"id":"9ab94adbe6758ed1","repo":"datawhalechina/hello-agents","slug":"too-many-files-in-patch-len-set-touched-files","errorCode":null,"errorMessage":"Too many files in patch: {len(set(touched_files))} > {self.max_files}","messagePattern":"Too many files in patch: (.+?) > (.+?)","errorType":"exception","errorClass":"PatchApplyError","httpStatus":null,"severity":"warning","filePath":"Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py","lineNumber":116,"sourceCode":"        3. 创建备份目录\n        4. 逐个执行操作 (先备份再修改)\n        \n        参数:\n            patch_text: 符合 Codex 风格的补丁文本，以 *** Begin Patch 开始，*** End Patch 结束\n            \n        返回:\n            ApplyResult: 包含被修改文件和备份文件信息的结果对象\n            \n        异常:\n            PatchApplyError: 当补丁不符合格式、超出限制或应用失败时抛出\n        \"\"\"\n        # 解析补丁文本，提取操作列表\n        ops = self._parse_patch(patch_text)\n        \n        # 统计受影响的文件数量，检查是否超过限制\n        touched_files = [op[1] for op in ops if op[0] in {\"add\", \"update\", \"delete\"}]\n        if len(set(touched_files)) > self.max_files:\n            raise PatchApplyError(f\"Too many files in patch: {len(set(touched_files))} > {self.max_files}\")\n\n        # 估算补丁修改的总行数，检查是否超过限制\n        total_changed = self._estimate_changed_lines(ops)\n        if total_changed > self.max_total_changed_lines:\n            raise PatchApplyError(f\"Patch too large: {total_changed} changed lines > {self.max_total_changed_lines}\")\n\n        # 创建本次补丁应用的专属备份目录（时间戳命名）\n        backup_run_dir = self.backups_dir / datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n        backup_run_dir.mkdir(parents=True, exist_ok=True)\n\n        # 初始化结果收集变量\n        files_changed: List[str] = []  # 记录被修改的文件路径\n        backups: List[str] = []  # 记录创建的备份文件路径\n\n        # 遍历所有解析出的操作，逐个执行\n        for kind, rel_path, payload in ops:\n            # 安全检查：确保路径在仓库内，防止路径遍历攻击\n            target = self._safe_path(rel_path)","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py#L98-L134","documentation":"PatchApplyError raised by ApplyPatchExecutor when the number of distinct files touched by add/update/delete operations exceeds the executor's configured max_files limit. This is a guardrail against overly broad agent-generated patches; parsing succeeds but execution is refused before any file is modified.","triggerScenarios":"Submitting a patch whose set of '*** Add File'/'*** Update File'/'*** Delete File' targets exceeds max_files (e.g. 10 files with a limit of 5). Fails atomically — no backups or writes happen.","commonSituations":"LLM agent attempting a large refactor in one patch; limit lowered in config after workflows were built; batch scripts generating multi-file patches without chunking.","solutions":["Split the patch into multiple smaller apply calls, each under the file limit.","Reconsider scope: a focused patch per logical change is the intended usage.","If the broad change is genuinely required, raise executor max_files in its constructor/config — but treat this as a policy decision, not a quick fix.","Check the error message: it reports actual vs allowed counts."],"exampleFix":"# before\nexecutor.apply(big_patch)  # touches 12 files, max_files=10 -> PatchApplyError\n\n# after\nfor chunk in split_patch_by_file(big_patch, max_files=executor.max_files):\n    result = executor.apply(chunk)","handlingStrategy":"validation","validationCode":"ops = parse_patch(patch_text)\ntouched = {op.path for op in ops if op.kind in {\"add\", \"update\", \"delete\"}}\nassert len(touched) <= executor.max_files, f\"split patch: {len(touched)} > {executor.max_files}\"","typeGuard":null,"tryCatchPattern":"try:\n    result = executor.apply(patch_text)\nexcept PatchApplyError as e:\n    if str(e).startswith(\"Too many files\"):\n        for chunk in split_patch_by_file(patch_text, executor.max_files):\n            executor.apply(chunk)\n    else:\n        raise","preventionTips":["Generate one patch per logical change instead of repo-wide refactors.","Pre-check file counts against executor.max_files before submitting.","Expose max_files in config so policy changes are deliberate, not ad hoc."],"tags":["python","patching","guardrail","code-agent"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}