{"record":{"id":"ab013bf73f19c811","repo":"Hmbown/CodeWhale","slug":"external-credential-consent-for-uses-unsupporte","errorCode":null,"errorMessage":"external credential consent for {} uses unsupported version {}; revoke and consent again","messagePattern":"external credential consent for (.+?) uses unsupported version (.+?); revoke and consent again","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/config/src/external_credentials.rs","lineNumber":414,"sourceCode":"        &self,\n        provider: ProviderKind,\n        source: ExternalCredentialSource,\n        resolved_path: &Path,\n    ) -> Result<()> {\n        if self.access == ExternalCredentialAccess::Disabled {\n            bail!(\n                \"external credential access is disabled for {}\",\n                provider.as_str()\n            );\n        }\n        if self.access == ExternalCredentialAccess::Managed {\n            bail!(\n                \"managed external credential access is unsupported for {}; no schema-safe preservation adapter is available\",\n                provider.as_str()\n            );\n        }\n        if self.consent_version != EXTERNAL_CREDENTIAL_CONSENT_VERSION {\n            bail!(\n                \"external credential consent for {} uses unsupported version {}; revoke and consent again\",\n                provider.as_str(),\n                self.consent_version\n            );\n        }\n        if self.provider != provider.as_str() {\n            bail!(\n                \"external credential consent is scoped to provider {:?}, not {}\",\n                self.provider,\n                provider.as_str()\n            );\n        }\n        if self.source != source {\n            bail!(\n                \"external credential consent source mismatch for {} (expected {})\",\n                provider.as_str(),\n                source.as_str()\n            );","sourceCodeStart":396,"sourceCodeEnd":432,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/config/src/external_credentials.rs#L396-L432","documentation":"Each stored consent is stamped with EXTERNAL_CREDENTIAL_CONSENT_VERSION (currently 1); validate_read_scope() refuses to honor a record whose version differs, because the consent semantics may have changed between versions. The correct recovery — named in the message — is to revoke the old consent and consent again under the current version.","triggerScenarios":"A consent record in config carries consent_version != 1 (e.g. 0 from an earlier Codewhale, or 2 from a newer one) and is validated for use.","commonSituations":"Downgrading Codewhale after a consent created by a newer version; consent files written by pre-release/experimental builds; hand-editing or restoring an old config backup that carries stale consent records.","solutions":["Revoke the stale consent and consent again with the current Codewhale version","If it came from a backup restore, expect one-time re-consent per credential","Keep consent records out of config backups/sync so version skew cannot follow you between machines"],"exampleFix":"# before: consent_version = 0 (from an older build)\n\n# after\n$ codewhale credentials revoke <provider>\n$ codewhale credentials consent <provider> --source path --path /keys/acme.env\n# re-creates the record with consent_version = 1","handlingStrategy":"try-catch","validationCode":"if consent.consent_version != EXTERNAL_CREDENTIAL_CONSENT_VERSION {\n    // flag as stale and route to revoke + re-consent before any read\n}","typeGuard":"fn consent_version_is_current(c: &ExternalCredentialConsent) -> bool {\n    c.consent_version == EXTERNAL_CREDENTIAL_CONSENT_VERSION\n}","tryCatchPattern":"match consent.validate_read_scope(provider, source, &path) {\n    Ok(()) => read_external_credential(&path),\n    Err(e) if e.to_string().contains(\"unsupported version\") => {\n        revoke_and_reconsent(provider).await // the documented recovery\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Expect one re-consent per credential after upgrading/downgrading Codewhale","Exclude consent records from config backups and machine-to-machine sync","Check consent_version when restoring old configs before use"],"tags":["security","consent","version-mismatch","credentials"],"backgroundTag":"consent-version-mismatch","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}