{"record":{"id":"3f37df0ba2f5dc6e","repo":"windmill-labs/windmill","slug":"impossible-to-parse-arg-digit","errorCode":null,"errorMessage":"Impossible to parse arg digit","messagePattern":"Impossible to parse arg digit","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/parsers/windmill-parser-bash/src/lib.rs","lineNumber":119,"sourceCode":"        })\n    } else {\n        Err(anyhow!(\"Error parsing powershell script\".to_string()))\n    }\n}\n\nlazy_static::lazy_static! {\n    static ref RE_BASH: Regex = Regex::new(r#\"(?m)^(\\w+)=\"\\$(?:(\\d+)|\\{(\\d+)\\}|\\{(\\d+):-(.*)\\})\"(?:[\\t ]*)?(?:#.*)?\\r?$\"#).unwrap();\n}\n\nfn parse_bash_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {\n    let mut hm: HashMap<i32, (String, Option<String>)> = HashMap::new();\n    for cap in RE_BASH.captures_iter(code) {\n        hm.insert(\n            cap.get(2)\n                .or(cap.get(3))\n                .or(cap.get(4))\n                .and_then(|x| x.as_str().parse::<i32>().ok())\n                .ok_or_else(|| anyhow!(\"Impossible to parse arg digit\"))?,\n            (\n                cap[1].to_string(),\n                cap.get(5).map(|x| x.as_str().to_string()),\n            ),\n        );\n    }\n    let mut args = vec![];\n    for i in 1..20 {\n        if hm.contains_key(&i) {\n            let (name, default) = hm.get(&i).unwrap();\n            args.push(Arg {\n                name: name.clone(),\n                typ: Typ::Str(None),\n                default: default.clone().map(|x| json!(x)),\n                otyp: None,\n                has_default: default.is_some(),\n                oidx: None,\n                otyp_inferred: false,","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/parsers/windmill-parser-bash/src/lib.rs#L101-L137","documentation":"While building the Bash signature, the parser maps each captured positional index (`$1`, `${2}`, `${3:-default}`) to an i32 via capture groups 2/3/4 of RE_BASH. If none of those groups is present or the digits can't parse, it errors with this message — an inconsistency between the regex alternations and the capture-conversion code, normally not user-triggerable.","triggerScenarios":"A script line matched RE_BASH where groups 2/3/4 are all None or non-numeric — practically triggered by regex/code drift (an alternation added to the regex whose digit capture isn't in the `.or(...)` chain) or exotic input matching an uncovered alternation.","commonSituations":"Custom forks or patches to RE_BASH adding new alternations without extending the `.get(2).or(get(3)).or(get(4))` chain; scripts with oddly formatted arg lines hitting an edge alternation.","solutions":["Rewrite the offending `$N`-style line in the script to the canonical `name=\"$1\"` form","If RE_BASH was patched, extend the capture chain (`.or(cap.get(N))`) and the i32 parse to cover the new alternation","Report upstream if a plain `var=\"$1\"` line triggers it — likely a parser bug"],"exampleFix":"// before\n.and_then(|x| x.as_str().parse::<i32>().ok())\n// after (when a new capture group 6 was added to RE_BASH)\n.or(cap.get(6))\n.and_then(|x| x.as_str().parse::<i32>().ok())","handlingStrategy":"type-guard","validationCode":"// only submit scripts with canonical arg assignments\nconst canon = /^\\w+=\"\\$(?:\\d+|\\{\\d+\\}|\\{\\d+:-.*\\})\"/m;\nif (!canon.test(code)) throw new Error('no canonical bash positional args');","typeGuard":"fn has_canonical_bash_args(code: &str) -> bool {\n    lazy_static::lazy_static! {\n        static ref RE: regex::Regex = regex::Regex::new(\n            r#\"^\\w+=\"\\$(?:\\d+|\\{\\d+\\}|\\{\\d+:-.*\\})\"\"#).unwrap();\n    }\n    RE.is_match(code)\n}","tryCatchPattern":null,"preventionTips":["Keep positional-arg assignments in the canonical form the regex documents","Any change to RE_BASH must update the capture-or-chain and add a test","Keep the regex and the numeric conversion adjacent so drift is visible in review"],"tags":["bash","parser","regex","internal-invariant"],"backgroundTag":"regex-capture-parse-failed","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}