{"record":{"id":"ae444a7a23a96fca","repo":"windmill-labs/windmill","slug":"error-parsing-code-for-imports","errorCode":null,"errorMessage":"Error parsing code for imports: {}","messagePattern":"Error parsing code for imports: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/parsers/windmill-parser-py-imports/src/lib.rs","lineNumber":190,"sourceCode":"        .lines()\n        .last()\n        .map(|x| x.starts_with(\"@\"))\n        .unwrap_or(false)\n    {\n        code = code\n            .lines()\n            .take(code.lines().count() - 1)\n            .collect::<Vec<&str>>()\n            .join(\"\\n\")\n            + \"\\n\";\n    }\n\n    // Add a fake main function to ensure the parser can process the code correctly\n    // This is needed because we've split off the real main function above\n    let code_with_fake_main = format!(\"{}\\n\\ndef main(): pass\", code);\n\n    let ast = Suite::parse(&code_with_fake_main, \"main.py\").map_err(|e| {\n        anyhow::anyhow!(\"Error parsing code for imports: {}\", e.to_string())\n    })?;\n    // Note: We're still using the original code for finding pins,\n    // as the TextRange values from the parsed AST would be based on code_with_fake_main\n    // but we want to match against the original code\n    let find_pin = |range: TextRange, key: String| {\n        let hs = code\n            .chars()\n            .skip(range.end().to_usize())\n            .take_while(|e| *e != '\\n')\n            .collect::<String>();\n\n        if hs.trim_start().is_empty() {\n            return None;\n        }\n\n        PIN_RE.captures(&hs).and_then(|x| {\n            x.get(1).zip(x.get(2)).and_then(|(ty_m, pkg_m)| {\n                let pkg = pkg_m.as_str().to_owned();","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/parsers/windmill-parser-py-imports/src/lib.rs#L172-L208","documentation":"parse_code_for_imports in windmill-parser-py-imports parses the code (with a fake 'def main(): pass' appended so the module still parses after the real main was split off) using ruff's Suite::parse. If that parse fails, the error is rethrown as 'Error parsing code for imports: ...'.","triggerScenarios":"Calling parse_code_for_imports (directly or via parse_relative_imports / parse_python_imports) on Python code that is syntactically invalid — the appended fake main does not fix broken module-level syntax such as unbalanced brackets, bad indentation, or stray tokens.","commonSituations":"Analyzing partially-written scripts, code stored with wrong encoding producing mojibake, snippets extracted from larger files losing their enclosing block, or files with Windows/mac mixed line endings confusing indentation-sensitive parsing.","solutions":["Read the wrapped message after 'Error parsing code for imports:' for the exact offending line/column and fix it in the original file.","Run 'python -m py_compile' on the source to confirm it is valid standalone Python.","Ensure the code passed in is the complete module body (not a fragment whose enclosing block was cut off).","Check encoding: re-save the file as UTF-8 without BOM and normalize line endings."],"exampleFix":"// before (fragment passed to the import parser)\n    return x + 1\n\n// after (complete module passed)\ndef add(x):\n    return x + 1","handlingStrategy":"validation","validationCode":"import ast\ndef validate_code_for_imports(code: str) -> None:\n    # parse the same augmented form the parser builds (code + fake main)\n    try:\n        ast.parse(code + '\\n\\ndef main(): pass')\n    except SyntaxError as e:\n        raise SystemExit(f'Code invalid for import analysis, line {e.lineno}: {e.msg}')","typeGuard":null,"tryCatchPattern":"try:\n    imports = parse_python_imports(code)\nexcept Exception as e:\n    if 'Error parsing code for imports:' in str(e):\n        raise RuntimeError(f'Fix module syntax: {e}') from e\n    raise","preventionTips":["Pass complete module bodies, not fragments cut from larger files","Check the module parses standalone with ast.parse before analysis","Normalize encoding to UTF-8 and consistent line endings","Fix the reported line/column in the wrapped error message first"],"tags":["python","parser","imports","syntax-error"],"backgroundTag":"syntax-error","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"}