windmill-labs/windmill · error

Error parsing bash script

Error message

Error parsing bash script

What it means

`parse_bash_sig` extracts a Bash script's signature by matching `VAR="$1"`-style positional-argument assignments against RE_BASH. If no expected pattern matches (the parser cannot extract any parameters), it returns this generic error instead of a signature.

Source

Thrown at backend/parsers/windmill-parser-bash/src/lib.rs:28

use serde_json::json;

use std::{collections::HashMap, str::FromStr};
use windmill_parser::{Arg, MainArgSignature, ObjectType, Typ};

pub fn parse_bash_sig(code: &str) -> anyhow::Result<MainArgSignature> {
    let parsed = parse_bash_file(&code)?;
    if let Some(x) = parsed {
        let args = x;
        Ok(MainArgSignature {
            star_args: false,
            star_kwargs: false,
            args,
            auto_kind: None,
            has_preprocessor: None,
            ..Default::default()
        })
    } else {
        Err(anyhow!("Error parsing bash script".to_string()))
    }
}

/// PowerShell common parameter names that are automatically added by [CmdletBinding()].
/// These should be filtered from the parsed signature since they are not user-defined.
const POWERSHELL_COMMON_PARAMS: &[&str] = &[
    "verbose",
    "debug",
    "erroraction",
    "errorvariable",
    "informationaction",
    "informationvariable",
    "outvariable",
    "outbuffer",
    "pipelinevariable",
    "warningaction",
    "warningvariable",
    "whatif",

View on GitHub (pinned to e474e8803c)

Solutions

  1. Rewrite parameter handling as top-level assignments of the form `param_name="$1"`, `param_name="${1}"`, or with a default `param_name="${1:-default}"` — one per positional arg
  2. Ensure each assignment matches the pattern exactly: `\w+` name, value exactly `$N`, `${N}`, or `${N:-default}`, optionally with a trailing comment
  3. Avoid getopts/shift-style parsing if you want Windmill to generate a UI signature from the script
  4. If the script needs no typed params, define them via Windmill's script metadata/UI instead of relying on inference

Example fix

# before
while getopts "n:" opt; do case $opt in n) name=$OPTARG;; esac; done
# after
name="${1:-world}"
Defensive patterns

Strategy: validation

Validate before calling

// quick local check that param lines are parseable before deploying
const ok = /^\w+="\$(?:\d+|\{\d+\}|\{\d+:-.*\})"(\s*#.*)?$/m.test(code);

Type guard

function hasParseableBashParams(code) {
  return /^\w+="\$(?:\d+|\{\d+\}|\{\d+:-[^}]*\})"/m.test(code);
}

Try / catch

try { sig = parseBashSig(code); } catch (e) {
  if (e.message === 'Error parsing bash script') {
    // fall back to manually defined signature in script metadata
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the Bash parser on a script whose parameters don't match `name="$1"`, `name="${1}"`, or `name="${1:-default}"` — getopts/`read`-based args, `shift`/`$@` handling, `$1` used inline without a top-level assignment, or a script with no parseable arg lines.

Common situations: Scripts using getopts or long-option parsing libraries; positional args consumed inside expressions rather than via named assignment; scripts migrated from other shell tooling; authors expecting arbitrary bash arg parsing to be inferred.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/5831d30074156ac3. Report an issue: GitHub.