xai-org/grok-build · error · io::Error
serde_json parse error of auth store (wrapped as InvalidData
Error message
serde_json parse error of auth store (wrapped as InvalidData)
What it means
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.
Source
Thrown at crates/codegen/xai-grok-shell/src/auth/storage.rs:65
// Tighten world-readable copies (hand-restored, umask edge cases, etc.).
// Best-effort: a chmod failure must not block login/read paths.
if let Err(e) = crate::util::secure_file::ensure_owner_only_permissions(auth_file) {
tracing::warn!(
path = %auth_file.display(),
error = %e,
"auth: failed to enforce owner-only permissions on auth.json"
);
}
// Empty files are valid (recover from prior crash/partial write).
let trimmed = contents.trim();
if trimmed.is_empty() {
return Ok(AuthStore::new());
}
let map = serde_json::from_str(trimmed)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
Ok(map)
}
/// Read auth.json, returning an empty map if the file does not exist.
///
/// Non-empty corrupt JSON, permission errors, etc. are returned as errors
/// so the caller can decide whether to skip the write (to avoid clobbering
/// sibling scopes).
///
/// Kept for the test-only `persist_and_swap` and as a strict reader.
#[cfg_attr(
not(test),
expect(
dead_code,
reason = "used from tests only; remove expect when wired in production"
)
)]
pub(crate) fn read_auth_json_or_empty(auth_file: &Path) -> std::io::Result<AuthStore> {View on GitHub (pinned to bc7f02eddd)
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.
Example fix
// before: hand-edited file with trailing comma
{"tokens": {"default": {...}},}
// after: valid JSON, no trailing comma
{"tokens": {"default": {...}}} Defensive patterns
Strategy: validation
Validate before calling
// pre-check auth.json before the CLI reads it
let raw = std::fs::read_to_string("~/.grok/auth.json")?;
if !raw.trim().is_empty() {
serde_json::from_str::<serde_json::Value>(raw.trim())?; // surfaces syntax errors early
} Type guard
fn is_valid_auth_store(raw: &str) -> bool {
raw.trim().is_empty() || serde_json::from_str::<serde_json::Map<String, serde_json::Value>>(raw.trim()).is_ok()
} Try / catch
match read_auth_json(&path) {
Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
eprintln!("auth.json is corrupt: {e}; backing up and re-logging in");
std::fs::rename(&path, path.with_extension("json.bak"))?;
}
other => other?,
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to parse {}: {e}
- -32603
- Compaction checkpoint file corrupt: {checkpoint_path}. Canno
- {}
- Failed to load manifest: {e}
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/8d2c6d4f49e82491.
Report an issue: GitHub.