zeroclaw-labs/zeroclaw · error · anyhow::Error
invalid forge HTTP method `{}` (expected GET/POST/PATCH/PUT/
Error message
invalid forge HTTP method `{}` (expected GET/POST/PATCH/PUT/DELETE) What it means
forge_request parses the incoming ForgeApiRequest.method with ForgeMethod::parse, which accepts exactly GET, POST, PATCH, PUT, DELETE. Any other value — lowercase variants, HEAD, OPTIONS, or methods with stray whitespace — bails before any HTTP traffic reaches the forge.
Source
Thrown at crates/zeroclaw-channels/src/git/channel.rs:671
// `ghc_<id>` message ids name a comment; anything else reacts on
// the issue/PR body itself.
let target = match message_id.strip_prefix("ghc_") {
Some(comment_id) => ReactionTarget::Comment {
repo: issue.repo.clone(),
comment_id: comment_id.to_string(),
},
None => ReactionTarget::Issue(issue),
};
self.provider.add_reaction(&target, emoji).await?;
Ok(())
}
async fn forge_request(
&self,
request: zeroclaw_api::channel::ForgeApiRequest,
) -> anyhow::Result<zeroclaw_api::channel::ForgeApiResponse> {
let Some(method) = ForgeMethod::parse(&request.method) else {
anyhow::bail!(
"invalid forge HTTP method `{}` (expected GET/POST/PATCH/PUT/DELETE)",
request.method
);
};
let resp = self
.provider
.forge_request(ForgeRequest {
method,
path: request.path,
body: request.body,
})
.await?;
Ok(zeroclaw_api::channel::ForgeApiResponse {
status: resp.status,
body: resp.body,
})
}
}View on GitHub (pinned to 88bb9c8533)
Solutions
- Uppercase and whitelist the method before calling forge_request
- Restrict external input to the five supported verbs at the API boundary
- Map unsupported methods explicitly if you must accept them (e.g. HEAD → GET without body, OPTIONS → reject)
Example fix
// before
let req = ForgeApiRequest { method: "get".into(), .. }; // bails: lowercase
// after
let method = raw.trim().to_ascii_uppercase();
assert!(matches!(method.as_str(), "GET" | "POST" | "PATCH" | "PUT" | "DELETE"));
let req = ForgeApiRequest { method, .. }; Defensive patterns
Strategy: type-guard
Validate before calling
// Rust — normalize and restrict at the API boundary
let method = raw.trim().to_ascii_uppercase();
if supported_forge_method(&method).is_none() {
anyhow::bail!("method '{raw}' not supported; use GET/POST/PATCH/PUT/DELETE");
} Type guard
// Rust — narrow to the supported verbs before calling forge_request
fn supported_forge_method(raw: &str) -> Option<String> {
let m = raw.trim().to_ascii_uppercase();
matches!(m.as_str(), "GET" | "POST" | "PATCH" | "PUT" | "DELETE").then_some(m)
} Prevention
- Normalize HTTP methods to uppercase at the trust boundary
- Whitelist the five supported verbs for any user-supplied method input
When it happens
Trigger: Calling the channel's forge_request API with method = "get" (lowercase), "head", "options", or a user-supplied method forwarded unvalidated from glue code.
Common situations: Adapter code passing through HTTP methods from external input; case mismatches after a refactor; assuming HEAD/OPTIONS work because they are standard HTTP methods.
Related errors
- unknown git channel provider `{other}` (supported: github, g
- git channel `events` routing table ignores every event type;
- Path not allowed: contains null byte
- Path not allowed: parent-directory traversal is not allowed
- Commit message cannot be empty
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/d3902adac078702f.
Report an issue: GitHub.