{"record":{"id":"8d2c6d4f49e82491","repo":"xai-org/grok-build","slug":"serde-json-parse-error-of-auth-store-wrapped-as-i","errorCode":null,"errorMessage":"serde_json parse error of auth store (wrapped as InvalidData)","messagePattern":"serde_json parse error of auth store \\(wrapped as InvalidData\\)","errorType":"error_code","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-shell/src/auth/storage.rs","lineNumber":65,"sourceCode":"\n    // Tighten world-readable copies (hand-restored, umask edge cases, etc.).\n    // Best-effort: a chmod failure must not block login/read paths.\n    if let Err(e) = crate::util::secure_file::ensure_owner_only_permissions(auth_file) {\n        tracing::warn!(\n            path = %auth_file.display(),\n            error = %e,\n            \"auth: failed to enforce owner-only permissions on auth.json\"\n        );\n    }\n\n    // Empty files are valid (recover from prior crash/partial write).\n    let trimmed = contents.trim();\n    if trimmed.is_empty() {\n        return Ok(AuthStore::new());\n    }\n\n    let map = serde_json::from_str(trimmed)\n        .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;\n    Ok(map)\n}\n\n/// Read auth.json, returning an empty map if the file does not exist.\n///\n/// Non-empty corrupt JSON, permission errors, etc. are returned as errors\n/// so the caller can decide whether to skip the write (to avoid clobbering\n/// sibling scopes).\n///\n/// Kept for the test-only `persist_and_swap` and as a strict reader.\n#[cfg_attr(\n    not(test),\n    expect(\n        dead_code,\n        reason = \"used from tests only; remove expect when wired in production\"\n    )\n)]\npub(crate) fn read_auth_json_or_empty(auth_file: &Path) -> std::io::Result<AuthStore> {","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-shell/src/auth/storage.rs#L47-L83","documentation":"read_auth_json parses auth.json with serde_json::from_str; if the file is non-empty but is not valid JSON matching the AuthStore shape, the serde error is wrapped in a std::io::Error with ErrorKind::InvalidData (storage.rs:64-65). Empty files are treated as an empty store, so this error only fires for genuinely corrupt/non-empty content.","triggerScenarios":"Reading auth.json that contains malformed JSON (truncated write, manual edit typo, wrong format such as TOML/YAML, or valid JSON that doesn't deserialize into AuthStore).","commonSituations":"Crash mid-write leaving a partial file; user hand-edited auth.json and broke syntax; another tool rewrote the file in a different format; encoding issues (BOM) at file start.","solutions":["Validate the file with `jq . auth.json` (or a JSON linter) and fix the syntax error, or restore from backup.","Back up then delete/rename the corrupt auth.json so the CLI regenerates it on next login.","If manually editing, keep the exact AuthStore JSON schema and save as plain UTF-8 without BOM."],"exampleFix":"// before: hand-edited file with trailing comma\n{\"tokens\": {\"default\": {...}},}\n// after: valid JSON, no trailing comma\n{\"tokens\": {\"default\": {...}}}","handlingStrategy":"validation","validationCode":"// pre-check auth.json before the CLI reads it\nlet raw = std::fs::read_to_string(\"~/.grok/auth.json\")?;\nif !raw.trim().is_empty() {\n    serde_json::from_str::<serde_json::Value>(raw.trim())?; // surfaces syntax errors early\n}","typeGuard":"fn is_valid_auth_store(raw: &str) -> bool {\n    raw.trim().is_empty() || serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(raw.trim()).is_ok()\n}","tryCatchPattern":"match read_auth_json(&path) {\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {\n        eprintln!(\"auth.json is corrupt: {e}; backing up and re-logging in\");\n        std::fs::rename(&path, path.with_extension(\"json.bak\"))?;\n    }\n    other => other?,\n}","preventionTips":["Never hand-edit auth.json while the CLI is running.","Validate JSON after any manual edit with `jq . auth.json`.","Keep the atomic write pattern intact; don't replace write paths with plain truncate+write.","Save as UTF-8 without BOM."],"tags":["serialization","json","file-io","auth-store"],"backgroundTag":"invalid-json-file","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}