Hmbown/CodeWhale · error

credential file is not valid credential JSON

Error message

credential file {} is not valid credential JSON

What it means

parse_auth_file deserializes the credential store file with serde_json before interpreting it as a map of credential entries. If the file content is not parseable JSON at all, this error names the offending path (OS-quoted). It guards against corrupt or hand-edited credential stores.

Solutions

  1. Open the quoted file and fix the JSON syntax, or delete the file and re-run the provider's login command to regenerate it.
  2. Restore the file from a backup or dotfile repo.
  3. Re-authenticate: run the provider's relogin hint (e.g. `grok login` or `codewhale auth ...`).

Example fix

// before: credentials.json contains
{ "xai": { "access_token": "..., // trailing comment, invalid JSON
// after
{ "xai": { "access_token": "..." } }
Defensive patterns

Strategy: validation

Validate before calling

const txt = fs.readFileSync(p, 'utf8'); try { JSON.parse(txt); } catch { fixOrDelete(p); }

Type guard

const isJson = (s) => { try { JSON.parse(s); return true; } catch { return false; } };

Try / catch

try { useCredentials(); } catch (e) { if (String(e).includes('not valid credential JSON')) { fs.rmSync(path); await relogin(); } }

Prevention

When it happens

Trigger: load/store code calls parse_auth_file with file contents that serde_json::from_str rejects — truncated writes, manual edits, binary content, or a placeholder written by another tool.

Common situations: Editing ~/.codewhale credentials by hand and leaving invalid JSON; disk-full or crash mid-write leaving a truncated file; a sync tool (dotfiles manager) replacing the file with a template.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/48324c590997afef. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/oauth.rs:1719

    let Some(raw) = crate::external_credentials::read_codewhale_owned_to_string(path)? else {
        return Ok(None);
    };
    parse_auth_file(&raw, path).map(Some)
}

fn load_owned_auth_file_from_store(
    store: &codewhale_config::XaiOAuthCredentialStore,
    name: &str,
) -> Result<Option<AuthFile>> {
    let Some(raw) = store.read_to_string(name)? else {
        return Ok(None);
    };
    parse_auth_file(&raw, &store.path_for(name)?).map(Some)
}

fn parse_auth_file(raw: &str, path: &Path) -> Result<AuthFile> {
    let value: Value = serde_json::from_str(raw).map_err(|_| {
        anyhow::anyhow!(
            "credential file {} is not valid credential JSON",
            codewhale_config::quote_os_path(path)
        )
    })?;
    let obj = value.as_object().ok_or_else(|| {
        anyhow::anyhow!(
            "credential file {} must be a JSON object of entries",
            codewhale_config::quote_os_path(path)
        )
    })?;
    let mut out = BTreeMap::new();
    for (k, v) in obj {
        match serde_json::from_value::<OwnedAuthEntry>(v.clone()) {
            Ok(entry) => {
                out.insert(k.clone(), entry);
            }
            Err(_) => {
                tracing::warn!(

View on GitHub (pinned to 73e0f67d83)