{"record":{"id":"357292ad7dd5d271","repo":"Hmbown/CodeWhale","slug":"stored-mcp-oauth-token-for-server-name-is-not","errorCode":null,"errorMessage":"stored MCP OAuth token for '{server_name}' is not valid credential JSON; contents were omitted","messagePattern":"stored MCP OAuth token for '(.+?)' is not valid credential JSON; contents were omitted","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp/oauth.rs","lineNumber":650,"sourceCode":"}\n\nfn load_oauth_tokens(server_name: &str, url: &str) -> Result<Option<StoredMcpOAuthTokens>> {\n    let secrets = codewhale_secrets::Secrets::auto_detect();\n    let key = store_key(server_name, url);\n    let Some(serialized) = secrets\n        .get(&key)\n        .with_context(|| format!(\"reading MCP OAuth token for '{server_name}'\"))?\n    else {\n        return Ok(None);\n    };\n    let mut tokens = parse_stored_oauth_tokens(&serialized, server_name)?;\n    refresh_expires_in_from_timestamp(&mut tokens);\n    Ok(Some(tokens))\n}\n\nfn parse_stored_oauth_tokens(serialized: &str, server_name: &str) -> Result<StoredMcpOAuthTokens> {\n    serde_json::from_str(serialized).map_err(|_| {\n        anyhow!(\n            \"stored MCP OAuth token for '{server_name}' is not valid credential JSON; contents were omitted\"\n        )\n    })\n}\n\nfn save_oauth_tokens(tokens: &StoredMcpOAuthTokens) -> Result<()> {\n    let secrets = codewhale_secrets::Secrets::auto_detect();\n    let key = store_key(&tokens.server_name, &tokens.url);\n    let serialized = serde_json::to_string(tokens).context(\"serializing MCP OAuth token\")?;\n    secrets\n        .set(&key, &serialized)\n        .with_context(|| format!(\"saving MCP OAuth token for '{}'\", tokens.server_name))\n}\n\nfn delete_oauth_tokens(server_name: &str, url: &str) -> Result<bool> {\n    let secrets = codewhale_secrets::Secrets::auto_detect();\n    let key = store_key(server_name, url);\n    let existed = secrets","sourceCodeStart":632,"sourceCodeEnd":668,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/mcp/oauth.rs#L632-L668","documentation":"Stored MCP OAuth tokens live in the OS secrets store under a key derived from server name and URL, serialized as JSON. On load, the raw value is deserialized into StoredMcpOAuthTokens; if it is not that JSON shape the load fails with this message, which intentionally omits the stored contents because they are credentials.","triggerScenarios":"load_oauth_tokens reads a store entry that is not StoredMcpOAuthTokens JSON - a corrupted entry, a manual edit of the key, or a different codewhale version that wrote another schema to the same key.","commonSituations":"Upgrading across versions that changed the token schema; a keychain entry damaged or synced between machines; a raw access token pasted into the store; the server URL changed so the derived key now collides with a foreign entry.","solutions":["Delete the stored entry for that server (via the secrets/keychain manager) so the next connect re-runs OAuth and stores fresh tokens","Re-authenticate the server (remove and re-add, or the login flow) to overwrite the entry","Ensure all codewhale binaries on the machine are the same version so they agree on the token schema"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Validate the stored token shape before relying on it:\nif let Some(serialized) = secrets.get(&store_key(server_name, url))? {\n    if serde_json::from_str::<StoredMcpOAuthTokens>(&serialized).is_err() {\n        // clear the unusable entry now so the next connect re-runs OAuth instead of failing later\n        secrets.delete(&store_key(server_name, url))?;\n    }\n}","typeGuard":"fn is_valid_stored_token(raw: &str) -> bool {\n    serde_json::from_str::<StoredMcpOAuthTokens>(raw).is_ok()\n}","tryCatchPattern":"match load_oauth_tokens(server_name, url).await {\n    Err(e) if e.to_string().contains(\"not valid credential JSON\") => {\n        // delete the corrupted secrets-store entry and fall back to the interactive OAuth flow\n    }\n    other => other,\n}","preventionTips":["Treat this error as 'credential store entry unusable': clear the entry and re-authenticate rather than debugging contents","Keep codewhale versions consistent across machines that share a secrets store","Never hand-edit stored OAuth entries; use the login flow to overwrite them"],"tags":["mcp","oauth","secrets","corruption"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}