{"record":{"id":"0c8718d8d4e9c1b5","repo":"xai-org/grok-build","slug":"models-list-response-missing-result","errorCode":null,"errorMessage":"models/list response missing result","messagePattern":"models/list response missing result","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/cli_models.rs","lineNumber":97,"sourceCode":"    let params = serde_json::value::to_raw_value(&serde_json::json!({}))?;\n    let resp: acp::ExtResponse = acp_send(\n        acp::ExtRequest::new(\"x.ai/models/list\", params.into()),\n        acp_tx,\n    )\n    .await?;\n    parse_models_list_response(resp.0.get())\n}\n/// Parse an `x.ai/models/list` payload; a handler error wins over a\n/// missing result.\nfn parse_models_list_response(raw: &str) -> Result<acp::SessionModelState> {\n    let parsed: crate::session::ExtMethodResult<acp::SessionModelState> =\n        serde_json::from_str(raw)?;\n    if let Some(err) = parsed.error {\n        anyhow::bail!(\"models/list failed: {err}\");\n    }\n    parsed\n        .result\n        .ok_or_else(|| anyhow::anyhow!(\"models/list response missing result\"))\n}\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::agent::auth_method::{LEGACY_XAI_API_KEY_ENV_VAR, XAI_API_KEY_ENV_VAR};\n    use crate::agent::config::Config;\n    use crate::auth::{AuthMode, GrokAuth};\n    use serial_test::serial;\n    use xai_grok_test_support::EnvGuard;\n    const EXPECTED_LOGIN_HOST: &str = \"grok.com\";\n    /// A session the compiled-in backend recognises as its own, which `AuthBackend::owns` requires.\n    fn session_credential() -> GrokAuth {\n        GrokAuth {\n            key: \"session-token\".into(),\n            auth_mode: AuthMode::WebLogin,\n            ..GrokAuth::test_default()\n        }\n    }","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/cli_models.rs#L79-L115","documentation":"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.","triggerScenarios":"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.","commonSituations":"Version mismatch between the shell and the agent/server; proxy stripping response fields; hitting the wrong endpoint that returns {} on success.","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"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// validate the response shape before use\nif parsed.get(\"result\").is_none() && parsed.get(\"error\").is_none() {\n    return Err(\"response has neither result nor error\".into());\n}","typeGuard":"fn has_models_result(v: &serde_json::Value) -> bool {\n    v.get(\"result\").is_some()\n}","tryCatchPattern":"match parse_models_list_response(raw).await {\n    Ok(models) => models,\n    Err(e) if e.to_string().contains(\"missing result\") => {\n        // fall back to a static/cached model list\n        cached_models()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Keep the shell and agent/server versions in sync","Log raw JSON-RPC responses for debugging","Verify models/list capability before calling it"],"tags":["json-rpc","mcp","api-response"],"backgroundTag":"json-rpc-missing-result","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}