Hmbown/CodeWhale · error
credential file must be a JSON object of entries
Error message
credential file {} must be a JSON object of entries What it means
After JSON parsing succeeds, parse_auth_file requires the top-level value to be a JSON object whose keys are credential entry names. Arrays, strings, numbers, or null at the top level produce this error. The schema is a map of named entries, not a bare credential.
Solutions
- Wrap the credential in a named entry: {"<entry-name>": { ...credential... }}.
- Delete the file and re-run the provider login to regenerate the correct shape.
- If migrating from another tool, use the documented import path (e.g. `codewhale auth xai-device` or the Grok CLI import) instead of hand-copying.
Example fix
// before
{ "access_token": "...", "refresh_token": "..." }
// after
{ "default": { "access_token": "...", "refresh_token": "..." } } Defensive patterns
Strategy: validation
Validate before calling
const v = JSON.parse(fs.readFileSync(p, 'utf8')); if (v === null || typeof v !== 'object' || Array.isArray(v)) restructure(p);
Type guard
const isEntryMap = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
Try / catch
try { useCredentials(); } catch (e) { if (String(e).includes('must be a JSON object of entries')) { await relogin(); } } Prevention
- Wrap imported credentials under a named entry key
- Use documented import commands instead of copying raw credential JSON
- Keep the top-level shape {"entry": {credential}} in any migration script
When it happens
Trigger: parse_auth_file receives valid JSON whose root is not an object — e.g. a file containing a single credential object instead of {"name": {...}}, or an array of entries.
Common situations: User pastes one provider's credential JSON (from another tool's export) directly into the store instead of nesting it under an entry name; a migration wrote the wrong shape.
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
- agy OAuth token JSON carries no access token member
- Codewhale stream-json line
- Codex credential file
- credential file is not valid credential JSON
- invalid : top level must be an object
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/977716ae625be3e0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/oauth.rs:1725
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!(
target: "codewhale::oauth",
"skipping unreadable owned auth entry"
);
}
}
}View on GitHub (pinned to 73e0f67d83)