xai-org/grok-build · error

failed to parse {}: {e}

Error message

failed to parse {}: {e}

What it means

After reading the auth file, read_auth_entry deserializes it into a BTreeMap<String, AuthEntry> with serde_json. If the content is not valid JSON for that shape, this error wraps the path and the serde error. Note that entries lacking refresh_token/oidc_issuer are filtered out later — this error is only about structural/JSON validity.

Source

Thrown at crates/codegen/xai-grok-workspace/src/hub_auth/mod.rs:110

/// Read the active OIDC entry and its scope key. The key is threaded to the
/// refresh write so rotation updates exactly the entry that was read.
///
/// When several OIDC entries qualify, pick the **latest `expires_at`** — the
/// entry the shell is actively refreshing. The previous first-key selection
/// was alphabetical and could rotate a *different principal's* RT chain than
/// the one the user's sessions use.
fn read_auth_entry(path: &Path) -> anyhow::Result<(String, AuthEntry)> {
    if !path.exists() {
        anyhow::bail!(
            "No auth credentials found at {}. Run `grok login` first.",
            path.display()
        );
    }

    let content = std::fs::read_to_string(path)
        .map_err(|e| anyhow::anyhow!("failed to read {}: {e}", path.display()))?;
    let entries: BTreeMap<String, AuthEntry> = serde_json::from_str(&content)
        .map_err(|e| anyhow::anyhow!("failed to parse {}: {e}", path.display()))?;

    entries
        .into_iter()
        .filter(|(_, e)| e.refresh_token.is_some() && e.oidc_issuer.is_some())
        // Strictly-greater comparison: ties (including all-`None`) keep the
        // first candidate in BTreeMap (alphabetical) order, so single-entry
        // and legacy no-`expires_at` files behave exactly as before.
        .fold(None::<(String, AuthEntry)>, |best, cand| match best {
            Some(b) if cand.1.expires_at <= b.1.expires_at => Some(b),
            _ => Some(cand),
        })
        .ok_or_else(|| {
            anyhow::anyhow!(
                "no OIDC auth entry found in {}. Run `grok login` first.",
                path.display()
            )
        })
}

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Validate the file: `python3 -m json.tool ~/.grok/auth.json` (or $GROK_HOME/auth.json) and fix syntax errors.
  2. Re-authenticate with `grok login` to regenerate a well-formed auth.json.
  3. Check the expires_at format — must be a parseable chrono/Utc datetime (RFC3339).
  4. Restore a backup of auth.json if the file was corrupted mid-write.

Example fix

// before: hand-edited, wrong type for expires_at
{ "hub": { "refresh_token": "r", "oidc_issuer": "https://i", "expires_at": "tomorrow" } }
// after
{ "hub": { "refresh_token": "r", "oidc_issuer": "https://i", "expires_at": "2026-09-01T00:00:00Z" } }
Defensive patterns

Strategy: validation

Validate before calling

let path = default_auth_path()?;
let content = std::fs::read_to_string(&path)?;
let v: serde_json::Value = serde_json::from_str(&content)
    .map_err(|e| anyhow::anyhow!("auth.json is not valid JSON: {e}"))?;
if !v.is_object() { anyhow::bail!("auth.json must be a JSON object of entries"); }
if let Some(exp) = v.pointer("/hub/expires_at") {
    if exp.as_str().and_then(|s| chrono::DateTime::parse_from_rfc3339(s).ok()).is_none() {
        anyhow::bail!("expires_at must be RFC3339, got: {exp}");
    }
}

Type guard

fn is_valid_auth_json(content: &str) -> bool {
    serde_json::from_str::<BTreeMap<String, serde_json::Value>>(content).is_ok()
}

Try / catch

match read_auth_entry().await {
    Ok(entry) => entry,
    Err(e) if e.to_string().starts_with("failed to parse") => {
        eprintln!("auth.json corrupted — run `grok login` to regenerate");
        prompt_relogin();
        return Err(e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling read_auth_entry (or `provider()`) when auth.json is truncated, contains JSON that is not an object of AuthEntry maps, has wrong field types (e.g. expires_at not an RFC3339 datetime), or was hand-edited/corrupted.

Common situations: Manual edits to auth.json that broke JSON syntax; an interrupted `grok login` write leaving a partial file; a format change between tool versions (older schema); another tool overwriting the file with different JSON.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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