NousResearch/hermes-agent · error · ValueError
patch content required
Error message
patch content required
What it means
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.
Source
Thrown at acp_adapter/edit_approval.py:158
paths.append(path)
for match in re.finditer(
r'^\*\*\*\s+Move\s+File:\s*(.+?)\s*->\s*(.+)$',
patch_body,
re.MULTILINE,
):
src = match.group(1).strip()
dst = match.group(2).strip()
if src:
paths.append(src)
if dst:
paths.append(dst)
return paths
def _proposal_for_patch_v4a(arguments: dict[str, Any]) -> EditProposal:
patch_body = arguments.get("patch")
if not isinstance(patch_body, str) or not patch_body:
raise ValueError("patch content required")
paths = _extract_v4a_patch_paths(patch_body)
if not paths:
raise ValueError("no file paths found in V4A patch")
proposal_path = paths[0] if len(paths) == 1 else ", ".join(paths)
old_text = _read_text_if_exists(paths[0]) if len(paths) == 1 else None
return EditProposal(
tool_name="patch",
path=proposal_path,
old_text=old_text,
# ACP only supports a single diff payload here. Surface the exact V4A
# patch content before execution so patch-mode calls are permissioned
# and denied patches cannot mutate.
new_text=patch_body,
arguments=dict(arguments),
)
View on GitHub (pinned to c896c09c42)
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.
Example fix
# before
patch_body = arguments.get("patch")
if not isinstance(patch_body, str) or not patch_body:
raise ValueError("patch content required")
# after — accept a structured hunks list by serializing it first
raw = arguments.get("patch")
if isinstance(raw, list):
raw = "\n".join(str(hunk) for hunk in raw)
if not isinstance(raw, str) or not raw:
raise ValueError("patch content required")
patch_body = raw Defensive patterns
Strategy: validation
Validate before calling
patch_body = arguments.get("patch")
if not isinstance(patch_body, str) or not patch_body.strip():
return invalid_params("patch call requires 'patch' as a non-empty unified-diff string") Type guard
def is_patch_payload(v: Any) -> bool:
return isinstance(v, str) and bool(v.strip()) Try / catch
try:
proposal = _proposal_for_patch_v4a(arguments)
except ValueError as err:
return {"error": {"code": -32602, "message": str(err)}} # client retries with a proper diff Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- old_string and new_string required
- no file paths found in V4A patch
- Cannot edit non-file path: {path}
- path required
- content required
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/babdfd469a08e17b.
Report an issue: GitHub.