{"record":{"id":"41baa48c7ea32ddb","repo":"jdx/mise","slug":"unclosed-brace-alternate-in-glob-pattern-pattern","errorCode":null,"errorMessage":"unclosed brace alternate in glob pattern {pattern:?}","messagePattern":"unclosed brace alternate in glob pattern (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/task/task_source_checker.rs","lineNumber":137,"sourceCode":"                        if let Some(mut nested) = find_group(&pattern[start + 1..idx])? {\n                            let offset = start + 1;\n                            nested.start += offset;\n                            nested.end += offset;\n                            for (branch_start, branch_end) in &mut nested.branches {\n                                *branch_start += offset;\n                                *branch_end += offset;\n                            }\n                            return Ok(Some(nested));\n                        }\n                        group_start = None;\n                        branches.clear();\n                    }\n                }\n                _ => {}\n            }\n        }\n        if group_depth != 0 {\n            bail!(\"unclosed brace alternate in glob pattern {pattern:?}\");\n        }\n        Ok(None)\n    }\n\n    fn expand(pattern: &str, expanded: &mut Vec<String>) -> Result<()> {\n        let Some(group) = find_group(pattern)? else {\n            if expanded.len() >= MAX_BRACE_EXPANSIONS {\n                bail!(\n                    \"glob pattern expands to more than {MAX_BRACE_EXPANSIONS} alternatives: {pattern:?}\"\n                );\n            }\n            let mut literal = String::with_capacity(pattern.len());\n            let mut escaped = false;\n            let mut class_depth = 0;\n            for ch in pattern.chars() {\n                if escaped {\n                    escaped = false;\n                    literal.push(ch);","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/task/task_source_checker.rs#L119-L155","documentation":"After scanning the whole glob pattern, find_group checks that every `{` opened a brace alternate was closed by a `}`. If group_depth is non-zero at end of input, an alternate was left open and the function bails with the offending pattern. This prevents partial/incorrect brace expansion of task globs.","triggerScenarios":"Supplying a task glob with an unterminated `{` group, e.g. `src/{a,b/*.ts`, via sources/outputs or file patterns processed by expand_glob_braces.","commonSituations":"Typo when writing multi-branch globs in mise.toml; a line got truncated when editing config; nested braces written for another glob flavor that mise doesn't parse the same way.","solutions":["Close the brace alternate with the matching `}` in the pattern","Split an overly complex pattern into multiple simpler entries","Escape literal `{` as `\\{` if brace expansion was not intended"],"exampleFix":"// before\noutputs = ['dist/{js,css/*.map']\n// after\noutputs = ['dist/{js,css}/*.map']","handlingStrategy":"validation","validationCode":"// js: ensure every '{' in a task glob has a matching '}'\nfunction hasClosedBraces(p) {\n  let d = 0;\n  for (const ch of p.replace(/\\\\./g, '')) {\n    if (ch === '{') d++;\n    if (ch === '}') d--;\n  }\n  return d === 0;\n}\nhasClosedBraces('dist/{js,css}/*.map'); // true","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Close brace groups on the same line you open them","Run the task once after editing sources/outputs to catch parse errors early","Keep alternates short and avoid deep nesting"],"tags":["glob","task","brace-expansion"],"backgroundTag":"invalid-regex-pattern","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}