windmill-labs/windmill · error

Error parsing code: {}

Error message

Error parsing code: {}

What it means

parse_python_signature in windmill-parser-py first checks should_parse_for_models(code); when Pydantic-style models are detected it parses the FULL file with ruff's Suite::parse to both detect models and extract the main function's arguments. A syntax error anywhere in the file surfaces as 'Error parsing code: ...' from this line.

Source

Thrown at backend/parsers/windmill-parser-py/src/lib.rs:314

/// skip_params is a micro optimization for when we just want to find the main
/// function without parsing all the params.
pub fn parse_python_signature(
    code: &str,
    override_main: Option<String>,
    skip_params: bool,
) -> anyhow::Result<MainArgSignature> {
    let main_name = override_main.unwrap_or("main".to_string());

    let has_preprocessor = !filter_non_main(code, "preprocessor").is_empty();

    // Optimization: Parse code only once
    // - If models detected: parse full code, extract main from it, keep AST for type detection
    // - If no models: parse only the filtered main function
    let (params, module) = if should_parse_for_models(code) {
        // Parse full code once for both Pydantic detection and signature extraction
        let ast = Suite::parse(code, "main.py")
            .map_err(|e| anyhow::anyhow!("Error parsing code: {}", e.to_string()))?;

        // Extract main function from full AST
        let params = ast.iter().find_map(|x| match x {
            Stmt::FunctionDef(StmtFunctionDef { name, args, .. }) if name == &main_name => {
                Some(args.as_ref().clone())
            }
            Stmt::AsyncFunctionDef(StmtAsyncFunctionDef { name, args, .. })
                if name == &main_name =>
            {
                Some(args.as_ref().clone())
            }
            _ => None,
        });

        // Keep AST for Pydantic/dataclass detection
        (params, Some(ast))
    } else {
        // No models detected - parse only the filtered main function

View on GitHub (pinned to e474e8803c)

Solutions

  1. Read the wrapped message for the exact line/column and fix the syntax error in the file.
  2. Validate with 'python -m py_compile main.py' before deploying.
  3. Remove template placeholders, smart quotes, or truncated blocks.
  4. Note the full-file parse is triggered by model definitions: even fixing only near 'def main' is not enough — the whole file must be valid Python.
  5. Confirm the syntax features used match the Python version the parser targets.

Example fix

// before
class Item(BaseModel):
    name: str
    price int

// after
class Item(BaseModel):
    name: str
    price: int
Defensive patterns

Strategy: validation

Validate before calling

import ast
def validate_full_python(code: str) -> None:
    # model-detection forces a FULL-file parse, so validate the entire file
    try:
        ast.parse(code)
    except SyntaxError as e:
        raise SystemExit(f'line {e.lineno}: {e.msg}')

Try / catch

try:
    sig = parse_python_signature(code)
except Exception as e:
    if 'Error parsing code:' in str(e):
        raise RuntimeError(f'Fix Python syntax (whole file is parsed when models are present): {e}') from e
    raise

Prevention

When it happens

Trigger: Calling parse_python_signature on a script that contains model definitions (so the full-file parse path is taken) and has a syntax error anywhere in the file — including code far from the main function that the filtered path would have skipped.

Common situations: Pydantic/dataclass-based scripts with an unrelated syntax error in helper functions, Python-version-mismatched syntax, or template placeholders left in generated model files.

Related errors


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