{"record":{"id":"36cb5e2db9d8ffe6","repo":"Hmbown/CodeWhale","slug":"external-credential-consent-for-error","errorCode":null,"errorMessage":"external credential consent for {}: {error}","messagePattern":"external credential consent for (.+?): (.+?)","errorType":"console","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/config.rs","lineNumber":5990,"sourceCode":"            .metadata()\n            .map(codewhale_config::provider::Provider::kind)\n            .context(\"external credentials are unsupported for this provider\")?;\n        let consent = self\n            .provider_config_for(provider)\n            .and_then(|entry| entry.external_credentials.as_ref())\n            .with_context(|| {\n                format!(\n                    \"External credentials owned by {} are disabled for {}. To allow read-only access to this exact file, run:\\n  codewhale auth external-consent --provider {} --mode read-only --path {}\",\n                    source.as_str(),\n                    provider.display_name(),\n                    kind.as_str(),\n                    codewhale_config::quote_os_path(suggested_path)\n                )\n            })?;\n        consent\n            .read_grant(kind, source, &consent.path)\n            .map_err(|error| {\n                anyhow::anyhow!(\n                    \"external credential consent for {}: {error}\",\n                    provider.display_name()\n                )\n            })\n    }\n\n    /// Whether a structurally valid read-only consent record exists for an\n    /// external credential source. This never stats or reads the selected\n    /// file and never mints the capability required to do so.\n    pub(crate) fn external_credential_read_consent_configured(\n        &self,\n        provider: ApiProvider,\n        source: codewhale_config::ExternalCredentialSource,\n    ) -> bool {\n        let Some(kind) = provider\n            .metadata()\n            .map(codewhale_config::provider::Provider::kind)\n        else {","sourceCodeStart":5972,"sourceCodeEnd":6008,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/config.rs#L5972-L6008","documentation":"Inside external_credential_read_grant(), after a consent record is found it is re-validated by consent.read_grant(kind, source, &consent.path); any failure is wrapped as 'external credential consent for {provider}'. Failures mean the persisted consent record no longer matches the request: wrong source kind, path moved, mode is not read-only, or the record structure is stale.","triggerScenarios":"The external CLI moved or rewrote its credential file after consent was granted; consent recorded for a different ExternalCredentialSource or provider kind; partial/corrupted TOML consent entry; CLI upgrade changed the file path.","commonSituations":"Grok/Codex CLI reinstalled under a new HOME or new path; consent granted on macOS then synced to Linux; manually edited config files.","solutions":["Re-issue consent for the exact current file: codewhale auth external-consent --provider <provider> --mode read-only --path <file>.","Verify the path in the persisted consent record still exists and matches the CLI's real credential file.","Remove the stale [external_credentials] entry and grant fresh consent."],"exampleFix":"# before: stale consent path\n[external_credentials.xai]\nmode = \"read-only\"\npath = \"/old/home/.grok/auth.json\"\n\n# after: re-grant against the real file\n# codewhale auth external-consent --provider xai --mode read-only --path ~/.grok/auth.json","handlingStrategy":"try-catch","validationCode":"// cheap structural probe before attempting the grant (never stats/reads the file)\nif !config.external_credential_read_consent_configured(provider, source) {\n    // surface re-consent guidance instead of hitting the wrapped error\n    return Ok(None);\n}","typeGuard":"fn external_consent_usable(config: &Config, provider: ApiProvider, source: ExternalCredentialSource) -> bool {\n    config.external_credential_read_consent_configured(provider, source)\n}","tryCatchPattern":"let grant = match config.external_credential_read_grant(provider, source, &path) {\n    Ok(g) => g,\n    Err(e) if e.to_string().starts_with(\"external credential consent for\") => {\n        // consent record stale/mismatched: prompt the user to re-run\n        // codewhale auth external-consent --provider <p> --mode read-only --path <file>\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n};","preventionTips":["Re-grant consent after reinstalling/moving the external CLI or changing HOME.","Never hand-edit persisted consent records.","Treat consent as pinned to one absolute path — symlink churn breaks it."],"tags":["rust","security","credentials","external-consent","config"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}