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

  1. Validate the file with `jq . auth.json` (or a JSON linter) and fix the syntax error, or restore from backup.
  2. Back up then delete/rename the corrupt auth.json so the CLI regenerates it on next login.
  3. 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

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

Related errors


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