Hmbown/CodeWhale · error
external credential file not found at
Error message
external credential file not found at {} What it means
When consuming another CLI's credential file under a read-only `ExternalCredentialReadGrant`, the file at the granted path does not exist (or is unreadable as a string), so it cannot be parsed into an `AuthFile`. The library quotes the OS path in the message to make the missing file obvious.
Solutions
- Run the other CLI's login first (e.g. `grok login`) so its credential file exists at the granted path.
- Verify the configured external credential path matches the real file (check `~/.config/<cli>/auth.json` or equivalent).
- Alternatively use Codewhale-owned storage via `codewhale auth xai-device` instead of importing.
Example fix
// before (config) external_credential_path = "/home/me/.grok/auth.json" // file absent // after $ grok login # creates the auth file codewhale ... # import now finds it
Defensive patterns
Strategy: validation
Validate before calling
use std::path::Path;
let path = grant.path();
if !Path::new(path).is_file() {
// run `grok login` first or fix the configured path before importing
} Type guard
fn external_credential_exists(grant: &ExternalCredentialReadGrant) -> bool {
std::path::Path::new(grant.path()).is_file()
} Prevention
- Run the external CLI's login before pointing Codewhale at its auth file.
- Verify the configured path after OS/HOME changes (the file usually lives under the user's config dir).
- Prefer Codewhale-owned storage (`codewhale auth xai-device`) when import is not required.
When it happens
Trigger: Calling `load_external_auth_file(grant)` where `crate::external_credentials::read_to_string(grant)` returns `None` — the path in the grant (`grant.path()`) has no file on disk.
Common situations: Pointing the external-credential grant at a path where `grok login` (or another CLI) never wrote its auth file; the other CLI not yet logged in; the file was deleted or lives under a different HOME; typo in the configured path.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- a CNB access token is not configured in the Codewhale…
- agy OAuth token JSON carries no access token member
- agy OAuth token member
- Antigravity import requires an agy_cli grant, not
- api_key cannot be empty string
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/ceff7f2f6684c323.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/oauth.rs:1773
store
.write(name, &serialized, allow_replace)
.with_context(|| {
format!(
"writing owned OAuth credentials to {}",
codewhale_config::quote_os_path(&store.directory().join(name))
)
})?;
#[cfg(test)]
crate::external_credentials::record_owned_credential_write();
Ok(())
}
/// Read-only parse of another CLI's granted credential file.
fn load_external_auth_file(
grant: &codewhale_config::ExternalCredentialReadGrant,
) -> Result<AuthFile> {
let Some(raw) = crate::external_credentials::read_to_string(grant)? else {
bail!(
"external credential file not found at {}",
codewhale_config::quote_os_path(grant.path())
);
};
parse_auth_file(&raw, grant.path())
}
fn select_entry(provider: OAuthProvider, file: &mut AuthFile) -> Option<(String, OwnedAuthEntry)> {
// Prefer this provider's registered client-id scope when present.
let preferred_suffix = format!("::{}", oauth_provider_params(provider).default_client_id);
if let Some((k, v)) = file
.iter()
.find(|(k, e)| k.ends_with(&preferred_suffix) && entry_has_usable_secret(e))
{
return Some((k.clone(), v.clone()));
}
file.iter()
.find(|(_, e)| entry_has_usable_secret(e))View on GitHub (pinned to 73e0f67d83)