{"record":{"id":"442e6974f098b88f","repo":"Hmbown/CodeWhale","slug":"external-credential-path-changed-for-consent-c","errorCode":null,"errorMessage":"external credential path changed for {}; consent covers {}, current path is {}","messagePattern":"external credential path changed for (.+?); consent covers (.+?), current path is (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/external_credentials.rs","lineNumber":410,"sourceCode":"                source.as_str()\n            );\n        }\n        if !self.path.is_absolute() {\n            bail!(\n                \"external credential consent path for {} must be absolute\",\n                provider.as_str()\n            );\n        }\n        let normalized = resolve_external_credential_path(&self.path)?;\n        if normalized != self.path {\n            bail!(\n                \"external credential consent path for {} must be lexically normalized: {}\",\n                provider.as_str(),\n                quote_os_path(&self.path)\n            );\n        }\n        if self.path != resolved_path {\n            bail!(\n                \"external credential path changed for {}; consent covers {}, current path is {}\",\n                provider.as_str(),\n                quote_os_path(&self.path),\n                quote_os_path(resolved_path)\n            );\n        }\n        Ok(())\n    }\n\n    /// Validate and mint the read capability consumed by credential adapters.\n    /// No filesystem operation occurs while validating the policy.\n    pub fn read_grant(\n        &self,\n        provider: ProviderKind,\n        source: ExternalCredentialSource,\n        resolved_path: &Path,\n    ) -> Result<ExternalCredentialReadGrant> {\n        self.validate_read_scope(provider, source, resolved_path)?;","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/config/src/external_credentials.rs#L392-L428","documentation":"Thrown by `ExternalCredentialConsentToml::validate_read_scope` when the consent record's path no longer equals the currently resolved credential path — the file the consent covers has moved, been replaced by a symlink, or been renamed since consent was given. The grant is invalidated rather than silently following the new location.","triggerScenarios":"Calling `read_grant` where `resolved_path` (freshly resolved at read time) differs from `self.path` recorded at consent time — e.g. the credential file was moved, renamed, or is now reached via a different symlink.","commonSituations":"User moved/rotated their credential file after consenting; the credential store migrated from one location to another in an upgrade; a symlink target changed.","solutions":["Revoke the old consent and re-consent against the credential's current location.","Restore the credential file to the path covered by the existing consent (or fix the symlink).","If a migration moved credential paths intentionally, re-run the consent flow as part of the migration."],"exampleFix":"// before: consent covers old path after file moved\nmv ~/.codewhale/creds/google.json ~/secrets/google.json\n// after: point the credential back or re-consent\nln -s ~/secrets/google.json ~/.codewhale/creds/google.json  # or revoke + re-consent","handlingStrategy":"validation","validationCode":"fn consent_covers_current_location(consent: &ExternalCredentialConsentToml) -> anyhow::Result<bool> {\n    Ok(resolve_external_credential_path(&consent.path)? == consent.path)\n}","typeGuard":null,"tryCatchPattern":"match store.read_grant(provider, source, &path) {\n    Err(e) if e.to_string().contains(\"path changed\") => {\n        // credential moved since consent: revoke and re-consent at the new location\n        store.revoke(provider)?;\n        run_consent_flow(provider)?;\n    }\n    other => other,\n}","preventionTips":["Keep credential files at stable paths; move files only with a re-consent step.","After any credential migration or upgrade, re-run the consent flow.","Warn users not to rename or move consented credential files."],"tags":["config","credentials","consent","path"],"backgroundTag":"invalid-config-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}