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

  1. Upgrade the agent/server so it implements models/list and returns a proper result
  2. Log and inspect the raw response to see what the server actually returned
  3. 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

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


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/0c8718d8d4e9c1b5. Report an issue: GitHub.