{"record":{"id":"ecd9cf4b1287e95f","repo":"openai/codex","slug":"glob-pattern-must-not-be-empty","errorCode":null,"errorMessage":"glob pattern must not be empty","messagePattern":"glob pattern must not be empty","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"codex-rs/network-proxy/src/mitm_hook.rs","lineNumber":517,"sourceCode":"        .map(|value| match parse_matcher_pattern(value)? {\n            MatcherPattern::Literal(value) => Ok(ValueMatcher::Exact(value.to_string())),\n            MatcherPattern::Glob(glob_pattern) => Ok(ValueMatcher::Glob(compile_glob_matcher(\n                glob_pattern,\n                /*literal_separator*/ false,\n            )?)),\n        })\n        .collect()\n}\n\nfn parse_matcher_pattern(pattern: &str) -> Result<MatcherPattern<'_>> {\n    if let Some(literal) = pattern.strip_prefix(LITERAL_PREFIX) {\n        return Ok(MatcherPattern::Literal(literal));\n    }\n    let Some(glob_pattern) = pattern.strip_prefix(PATTERN_PREFIX) else {\n        return Ok(MatcherPattern::Literal(pattern));\n    };\n    if glob_pattern.is_empty() {\n        return Err(anyhow!(\"glob pattern must not be empty\"));\n    }\n    Ok(MatcherPattern::Glob(glob_pattern))\n}\n\nfn compile_glob_matcher(pattern: &str, literal_separator: bool) -> Result<CompiledGlobMatcher> {\n    let mut builder = GlobBuilder::new(pattern);\n    builder\n        .backslash_escape(true)\n        .literal_separator(literal_separator);\n    builder\n        .build()\n        .map(|glob| CompiledGlobMatcher {\n            pattern: pattern.to_string(),\n            matcher: glob.compile_matcher(),\n        })\n        .map_err(|err| anyhow!(\"invalid glob pattern {pattern:?}: {err}\"))\n}\n","sourceCodeStart":499,"sourceCodeEnd":535,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/network-proxy/src/mitm_hook.rs#L499-L535","documentation":"Matcher strings prefixed with 'pattern:' are compiled as globset globs; 'pattern:' with nothing after the colon is an empty glob, which parse_matcher_pattern rejects with 'glob pattern must not be empty'. The rule applies wherever matchers are accepted: path_prefixes, query allowed-values, and header allowed-values.","triggerScenarios":"path_prefixes = [\"pattern:\"], or a query/header allowed-values list containing the exact string \"pattern:\" — any matcher equal to the bare prefix, from compile_path_matchers or compile_value_matchers.","commonSituations":"Template substitution meant to fill the glob body but rendered empty; deleting the pattern body while refactoring; expecting the bare prefix to mean 'match everything'.","solutions":["Put the glob after the colon, e.g. \"pattern:/api/*/items\"","Drop the 'pattern:' prefix entirely to treat the string as a literal","For 'match all paths' use \"/\" as a plain prefix entry instead of an empty glob"],"exampleFix":"# before\npath_prefixes = [\"pattern:\"]\n\n# after\npath_prefixes = [\"pattern:/api/*/items\"]","handlingStrategy":"validation","validationCode":"// Rust — no bare pattern: prefix\nlet values: Vec<&String> = config.mitm_hooks.iter()\n    .flat_map(|h| h.matcher.path_prefixes.iter()\n        .chain(h.matcher.query.values().flatten())\n        .chain(h.matcher.headers.values().flatten()))\n    .collect();\nif values.iter().any(|v| v.as_str() == \"pattern:\") {\n    return Err(anyhow!(\"empty glob after pattern: prefix\"));\n}","typeGuard":"fn matcher_is_well_formed(v: &str) -> bool {\n    v != \"pattern:\"\n}","tryCatchPattern":"match validate_mitm_hook_config(&config) {\n    Ok(()) => {}\n    Err(err) => eprintln!(\"{err:#}\"), // points at the field holding the empty glob\n}","preventionTips":["Never emit the pattern: prefix from templates without asserting a non-empty body","Prefer plain literals unless glob semantics are actually needed","Test glob-bearing config with the validator in CI"],"tags":["network","mitm","codex","config-validation","glob","path-matching"],"backgroundTag":"invalid-glob-pattern","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}