{"record":{"id":"e07fdf1ce14354da","repo":"jdx/mise","slug":"static-credential-globs","errorCode":null,"errorMessage":"static credential globs","messagePattern":"static credential globs","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/tracked.rs","lineNumber":638,"sourceCode":"/// Credential stores mise itself knows by name; they mean something only\n/// under the global configuration directory.\nfn credential_names() -> GlobSet {\n    glob_set(CREDENTIAL_NAMES)\n}\n\n/// Key material by name pattern, private wherever it is captured.\nfn credential_globs() -> GlobSet {\n    glob_set(CREDENTIAL_GLOBS)\n}\n\nfn glob_set(patterns: &[&str]) -> GlobSet {\n    let mut builder = GlobSetBuilder::new();\n    for pattern in patterns {\n        if let Ok(glob) = Glob::new(pattern) {\n            builder.add(glob);\n        }\n    }\n    builder.build().expect(\"static credential globs\")\n}\n\n/// The `[history] exclude` globs, applied in order with the last match\n/// deciding: a `!glob` after a broader glob re-includes what it matches.\n#[derive(Debug, Default)]\npub(crate) struct ExcludeSet {\n    patterns: Vec<(globset::GlobMatcher, bool)>,\n}\n\nimpl ExcludeSet {\n    pub(crate) fn new(globs: &[String]) -> Result<Self> {\n        let mut patterns = vec![];\n        for glob in globs {\n            let (pattern, negated) = match glob.strip_prefix('!') {\n                Some(rest) => (rest, true),\n                None => (glob.as_str(), false),\n            };\n            let expanded = file::replace_path(Path::new(pattern));","sourceCodeStart":620,"sourceCodeEnd":656,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/tracked.rs#L620-L656","documentation":"glob_set builds a GlobSet from patterns that were already filtered with Glob::new(... if let Ok), so builder.build() is expected to be infallible and is unwrapped with expect(\"static credential globs\"). A panic means GlobSetBuilder rejected a glob that Glob::new accepted, an upstream-inconsistency scenario.","triggerScenarios":"Practically unreachable for users; fires only if GlobSetBuilder::build fails on globs already validated by Glob::new, e.g. after a glob crate version change alters build() validation.","commonSituations":"Maintainers touching the credential glob builder after a glob/globset dependency update.","solutions":["Update the glob/globset crates to compatible versions","Verify the credential glob patterns compile with Glob::new in isolation if debugging","Replace expect with a graceful error if patterns ever become user-validated rather than compile-time static"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// verify patterns compile before use\nfor p in patterns {\n    Glob::new(p).expect(\"invalid credential glob pattern\");\n}","typeGuard":null,"tryCatchPattern":"let globset = builder.build()\n    .map_err(|e| anyhow!(\"failed to build credential globs: {e}\"))?;","preventionTips":["Keep glob and globset crate versions in sync","Unit-test credential glob construction with representative patterns","Prefer returning errors over expect even for 'infallible' builds"],"tags":["panic","glob","regex","invariant","credential"],"backgroundTag":"internal-invariant-violation","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}