{"record":{"id":"e166314454537992","repo":"Hmbown/CodeWhale","slug":"xai-grok-credential-file-must-be-a-json-object","errorCode":null,"errorMessage":"xAI/Grok credential file {} must be a JSON object of entries","messagePattern":"xAI/Grok credential file (.+?) must be a JSON object of entries","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/xai_oauth.rs","lineNumber":830,"sourceCode":") -> Result<AuthFile> {\n    let Some(raw) = crate::external_credentials::read_to_string(grant)? else {\n        bail!(\n            \"external xAI/Grok credential file not found at {}\",\n            codewhale_config::quote_os_path(grant.path())\n        );\n    };\n    parse_auth_file(&raw, grant.path())\n}\n\nfn parse_auth_file(raw: &str, path: &Path) -> Result<AuthFile> {\n    let value: Value = serde_json::from_str(raw).map_err(|_| {\n        anyhow::anyhow!(\n            \"xAI/Grok credential file {} is not valid credential JSON\",\n            codewhale_config::quote_os_path(path)\n        )\n    })?;\n    let obj = value.as_object().ok_or_else(|| {\n        anyhow::anyhow!(\n            \"xAI/Grok credential file {} must be a JSON object of entries\",\n            codewhale_config::quote_os_path(path)\n        )\n    })?;\n    let mut out = BTreeMap::new();\n    for (k, v) in obj {\n        match serde_json::from_value::<GrokAuthEntry>(v.clone()) {\n            Ok(entry) => {\n                out.insert(k.clone(), entry);\n            }\n            Err(_) => {\n                tracing::warn!(\n                    target: \"codewhale::xai_oauth\",\n                    \"skipping unreadable xAI auth entry\"\n                );\n            }\n        }\n    }","sourceCodeStart":812,"sourceCodeEnd":848,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/xai_oauth.rs#L812-L848","documentation":"Shape guard in parse_auth_file: the xAI/Grok credential file parsed as JSON but is not a JSON object of entries — it may be an array, string, or scalar. The schema contract requires an object keyed by entry names.","triggerScenarios":"Thrown at crates/tui/src/xai_oauth.rs:830 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Rewrite the credential file as a JSON object whose values are entry objects.","Re-authenticate (`grok login` or `codewhale auth xai-device`) to regenerate a correctly shaped file.","Check for incompatible tool versions that may have written an outdated schema."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}