xai-org/grok-build · error
models/list response missing result
Error message
models/list response missing result
What it means
parse_models_list_response deserializes a JSON-RPC models/list reply and returns the 'result' field, bailing if the response carries an 'error' or has no 'result'. This error means the reply parsed as valid JSON but contained neither an error nor a result — a malformed/unexpected server response.
Source
Thrown at crates/codegen/xai-grok-shell/src/cli_models.rs:97
let params = serde_json::value::to_raw_value(&serde_json::json!({}))?;
let resp: acp::ExtResponse = acp_send(
acp::ExtRequest::new("x.ai/models/list", params.into()),
acp_tx,
)
.await?;
parse_models_list_response(resp.0.get())
}
/// Parse an `x.ai/models/list` payload; a handler error wins over a
/// missing result.
fn parse_models_list_response(raw: &str) -> Result<acp::SessionModelState> {
let parsed: crate::session::ExtMethodResult<acp::SessionModelState> =
serde_json::from_str(raw)?;
if let Some(err) = parsed.error {
anyhow::bail!("models/list failed: {err}");
}
parsed
.result
.ok_or_else(|| anyhow::anyhow!("models/list response missing result"))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::agent::auth_method::{LEGACY_XAI_API_KEY_ENV_VAR, XAI_API_KEY_ENV_VAR};
use crate::agent::config::Config;
use crate::auth::{AuthMode, GrokAuth};
use serial_test::serial;
use xai_grok_test_support::EnvGuard;
const EXPECTED_LOGIN_HOST: &str = "grok.com";
/// A session the compiled-in backend recognises as its own, which `AuthBackend::owns` requires.
fn session_credential() -> GrokAuth {
GrokAuth {
key: "session-token".into(),
auth_mode: AuthMode::WebLogin,
..GrokAuth::test_default()
}
}View on GitHub (pinned to bc7f02eddd)
Solutions
- Upgrade the agent/server so it implements models/list and returns a proper result
- Log and inspect the raw response to see what the server actually returned
- Check for a proxy/middleware rewriting or filtering JSON-RPC responses
Defensive patterns
Strategy: fallback
Validate before calling
// validate the response shape before use
if parsed.get("result").is_none() && parsed.get("error").is_none() {
return Err("response has neither result nor error".into());
} Type guard
fn has_models_result(v: &serde_json::Value) -> bool {
v.get("result").is_some()
} Try / catch
match parse_models_list_response(raw).await {
Ok(models) => models,
Err(e) if e.to_string().contains("missing result") => {
// fall back to a static/cached model list
cached_models()
}
Err(e) => return Err(e),
} Prevention
- Keep the shell and agent/server versions in sync
- Log raw JSON-RPC responses for debugging
- Verify models/list capability before calling it
When it happens
Trigger: fetch_model_state sends models/list over the MCP/JSON-RPC channel and receives a response with neither result nor error fields — e.g. an empty object, a notification, or a response from an older server that doesn't implement models/list.
Common situations: Version mismatch between the shell and the agent/server; proxy stripping response fields; hitting the wrong endpoint that returns {} on success.
Related errors
- --header can only be used with HTTP or SSE servers.
- Invalid command '{command}': it looks like an environment va
- A URL is required for {label} servers. Usage: grok mcp add -
- Invalid URL '{url}'. Server URLs must start with http:// or
- Unexpected arguments after the URL: '{args}'. HTTP and SSE s
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/0c8718d8d4e9c1b5.
Report an issue: GitHub.