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
- Validate the file: `python3 -m json.tool ~/.grok/auth.json` (or $GROK_HOME/auth.json) and fix syntax errors.
- Re-authenticate with `grok login` to regenerate a well-formed auth.json.
- Check the expires_at format — must be a parseable chrono/Utc datetime (RFC3339).
- 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
- Never hand-edit auth.json; regenerate it with `grok login`
- Validate the file with a JSON linter after any manual inspection
- Keep expires_at in RFC3339/UTC format
- Ensure writes to auth.json are atomic (temp file + rename) to avoid truncation
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.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- auth entry '{scope_key}' not found while persisting refreshe
- produced JSON that is not a token payload: {e}
- failed to serialize MCP server {name}: {e}
- {}: root is not a JSON object
- {}: hooks is not a JSON object
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/fed7bd8ebe70c65b.
Report an issue: GitHub.