xai-org/grok-build · error
failed to build request: {e}
Error message
failed to build request: {e} What it means
This error is raised by `ext_call` in the worktree command module when `ext_request` cannot construct the JSON-RPC request for an ACP extension method call. The underlying cause is a serialization failure of the `params` argument or an invalid method string, wrapped via anyhow with the original formatter error. It aborts the worktree subcommand before anything is sent over the ACP transport.
Source
Thrown at crates/codegen/xai-grok-pager/src/worktree_cmd/mod.rs:139
method: &str,
params: &T,
) -> Result<acp::ExtRequest, serde_json::Error> {
let params = serde_json::value::to_raw_value(params)?;
Ok(acp::ExtRequest::new(method, params.into()))
}
/// ACP extension responses are wrapped in `{ "result": T, "error": ... }`.
#[derive(serde::Deserialize)]
struct ExtEnvelope<T> {
result: Option<T>,
error: Option<serde_json::Value>,
}
async fn ext_call<T: serde::de::DeserializeOwned>(
tx: &xai_acp_lib::AcpAgentTx,
method: &str,
params: &impl serde::Serialize,
) -> Result<T> {
let req =
ext_request(method, params).map_err(|e| anyhow::anyhow!("failed to build request: {e}"))?;
let resp = acp_send(req, tx)
.await
.map_err(|e| anyhow::anyhow!("{e}"))?;
let envelope: ExtEnvelope<T> = serde_json::from_str(resp.0.get())
.map_err(|e| anyhow::anyhow!("response parse error: {e}"))?;
if let Some(err) = envelope.error {
bail!("ACP error: {err}");
}
envelope
.result
.ok_or_else(|| anyhow::anyhow!("ACP response missing result field"))
}
async fn cmd_list(
tx: &xai_acp_lib::AcpAgentTx,
repo: Option<String>,
types: Vec<String>,
json: bool,
all: bool,View on GitHub (pinned to bc7f02eddd)
Solutions
- Inspect the inner `{e}` message to identify which params field failed to serialize.
- Check the params struct for types serde_json cannot represent (non-string map keys, f64::NAN, untagged enums that fail).
- Replace HashMap keys with String or BTreeMap<String, T> in the params type.
- Add a Serialize derive/unit test that round-trips the params struct to catch regressions early.
Example fix
// before
let params = serde_json::Map::new(); // built with non-string keys somewhere upstream
// after
#[derive(serde::Serialize)]
struct WorktreeListParams { repo: Option<String>, types: Vec<String> }
let params = WorktreeListParams { repo, types }; // guaranteed serializable Defensive patterns
Strategy: validation
Validate before calling
fn assert_serializable<T: serde::Serialize>(params: &T) -> Result<(), String> {
serde_json::to_value(params).map(|_| ()).map_err(|e| e.to_string())
}
// call before ext_call: assert_serializable(¶ms)?; Try / catch
match ext_call::<WorktreeList>(tx, "worktree/list", ¶ms).await {
Ok(list) => render(list),
Err(e) if e.to_string().contains("failed to build request") => {
eprintln!("params serialization failed: {e:#}");
}
Err(e) => eprintln!("worktree command failed: {e:#}"),
} Prevention
- Keep params types to serde_json-friendly shapes (String keys, no NaN floats).
- Add round-trip serialization unit tests for every extension params struct.
- Wrap ext_request in a debug assertion during CI to catch serialization issues before release.
When it happens
Trigger: Calling any worktree subcommand (list, show, rm, gc, db) whose params type fails `serde_json::to_value` serialization inside `ext_request`, e.g. params containing a non-string map key or a value serde_json rejects (NaN, non-string keys).
Common situations: A newly added CLI flag introduces a params field that fails to serialize; a params struct uses HashMap with non-string keys; serde feature mismatch after a dependency version change makes a field unserializable.
Related errors
- response parse error: {e}
- Invalid ACP content blocks: {e}
- Invalid ACP content blocks in "content": {e}
- ACP response missing result field
- -32602
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/cbada171066a8b19.
Report an issue: GitHub.