{"record":{"id":"babdfd469a08e17b","repo":"NousResearch/hermes-agent","slug":"patch-content-required","errorCode":null,"errorMessage":"patch content required","messagePattern":"patch content required","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"acp_adapter/edit_approval.py","lineNumber":158,"sourceCode":"            paths.append(path)\n    for match in re.finditer(\n        r'^\\*\\*\\*\\s+Move\\s+File:\\s*(.+?)\\s*->\\s*(.+)$',\n        patch_body,\n        re.MULTILINE,\n    ):\n        src = match.group(1).strip()\n        dst = match.group(2).strip()\n        if src:\n            paths.append(src)\n        if dst:\n            paths.append(dst)\n    return paths\n\n\ndef _proposal_for_patch_v4a(arguments: dict[str, Any]) -> EditProposal:\n    patch_body = arguments.get(\"patch\")\n    if not isinstance(patch_body, str) or not patch_body:\n        raise ValueError(\"patch content required\")\n\n    paths = _extract_v4a_patch_paths(patch_body)\n    if not paths:\n        raise ValueError(\"no file paths found in V4A patch\")\n\n    proposal_path = paths[0] if len(paths) == 1 else \", \".join(paths)\n    old_text = _read_text_if_exists(paths[0]) if len(paths) == 1 else None\n    return EditProposal(\n        tool_name=\"patch\",\n        path=proposal_path,\n        old_text=old_text,\n        # ACP only supports a single diff payload here.  Surface the exact V4A\n        # patch content before execution so patch-mode calls are permissioned\n        # and denied patches cannot mutate.\n        new_text=patch_body,\n        arguments=dict(arguments),\n    )\n","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/acp_adapter/edit_approval.py#L140-L176","documentation":"Raised by _proposal_for_patch_v4a in the ACP adapter when handling V4A protocol patch calls: the arguments' 'patch' field must be a non-empty string containing the diff payload used both to extract affected file paths and to show the user the exact change for approval. A missing, non-string, or empty patch field is rejected before parsing. This is a payload-shape error from the ACP client, not a filesystem or diff-application error.","triggerScenarios":"An ACP client sends a patch-mode call with patch omitted, null, an empty string, or a non-string (e.g. a list of hunks or an object) — commonly a protocol version mismatch where the client sends structured hunks while the adapter expects a single diff string.","commonSituations":"Editor extension upgrade changing the patch payload shape; agents splitting patches into multiple calls but sending the structure field empty; serialization bugs dropping large diff bodies.","solutions":["Send the full unified diff as a single string under arguments.patch.","Align the ACP client/extension and adapter versions so the patch payload schema matches.","If hunks arrive structured, serialize them to a unified diff string before dispatch.","Catch ValueError here and return an invalid-params response so the client can retry correctly."],"exampleFix":"# before\npatch_body = arguments.get(\"patch\")\nif not isinstance(patch_body, str) or not patch_body:\n    raise ValueError(\"patch content required\")\n\n# after — accept a structured hunks list by serializing it first\nraw = arguments.get(\"patch\")\nif isinstance(raw, list):\n    raw = \"\\n\".join(str(hunk) for hunk in raw)\nif not isinstance(raw, str) or not raw:\n    raise ValueError(\"patch content required\")\npatch_body = raw","handlingStrategy":"validation","validationCode":"patch_body = arguments.get(\"patch\")\nif not isinstance(patch_body, str) or not patch_body.strip():\n    return invalid_params(\"patch call requires 'patch' as a non-empty unified-diff string\")","typeGuard":"def is_patch_payload(v: Any) -> bool:\n    return isinstance(v, str) and bool(v.strip())","tryCatchPattern":"try:\n    proposal = _proposal_for_patch_v4a(arguments)\nexcept ValueError as err:\n    return {\"error\": {\"code\": -32602, \"message\": str(err)}}  # client retries with a proper diff","preventionTips":["Serialize structured hunks into one unified-diff string before sending","Pin client extension and adapter versions together","Log rejected payload shapes to catch schema drift early"],"tags":["acp","editor-integration","patch","validation","protocol","python"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}