windmill-labs/windmill · error
Cannot find main function.
Error message
Cannot find main function.
What it means
parse_nu_signature lexes the Nushell source looking for the token sequence `def` `main` `[`...args...`]` to extract the entrypoint's parameter list. If the tokens never produce an Args state (no `def main` found, or a malformed definition), it bails. Windmill requires Nushell scripts to expose a `def main` entrypoint to infer the argument signature.
Source
Thrown at backend/parsers/windmill-parser-nu/src/lib.rs:35
Args(String),
}
let mut last_token = LastToken::None;
for token in tokens {
let s = token.span;
let cont = src.get(s.start..s.end).ok_or(anyhow!("Parsing error"))?;
last_token = match last_token {
LastToken::None if cont == "def" => LastToken::Def,
LastToken::Def if cont == "main" => LastToken::Main,
LastToken::Main => {
LastToken::Args(cont.get(1..(cont.len() - 1)).unwrap_or("Error").to_owned())
}
LastToken::Args(_) => break,
_ => LastToken::None,
};
}
let LastToken::Args(args) = last_token else {
bail!("Cannot find main function.");
};
let mut sig = MainArgSignature::default();
sig.auto_kind = None;
let batches = args
.lines()
.filter_map(|el| {
if el.trim_start().starts_with('#') {
None
} else {
Some(
el.split(',')
.map(|el| el.trim())
.filter(|el| el != &"")
.collect::<Vec<&str>>(),
)
}View on GitHub (pinned to e474e8803c)
Solutions
- Add a `def main [ ... ] { ... }` entrypoint and move your logic/parameters into it.
- Keep the exact lowercase `def main` on adjacent tokens — no intervening code or unusual spacing between `def` and `main`.
- Name other helper functions something other than `main`, and make sure the entrypoint is literally `main`.
- Verify the parameter list is enclosed in square brackets `[]` right after `main`.
Example fix
// before
print "hello"
// after
def main [name: string] {
print $"hello ($name)"
} Defensive patterns
Strategy: validation
Validate before calling
function validateNuEntry(code) {
if (!/^\s*def\s+main\s*\[/m.test(code)) {
return 'Nushell scripts must define an entrypoint: def main [ ... ] { ... }';
}
return null;
} Try / catch
try {
const sig = parseNuSignature(source);
} catch (e) {
if (String(e).includes('Cannot find main function')) {
throw new Error('Add a `def main [args] { ... }` entrypoint; Windmill cannot infer the signature without it');
}
throw e;
} Prevention
- Always wrap script logic in `def main [...]` — never rely on top-level statements
- Keep `def` and `main` adjacent with plain spacing, no comments/strings between them
- Name helper functions anything other than `main`
When it happens
Trigger: Deploying a Nushell script that lacks `def main []` or `def main [...]`, defines main under a different name (`def run`), or has lexing quirks (e.g. `def` and `main` split by comments/odd spacing that reset the token state machine).
Common situations: Scripts written as plain command files with top-level statements and no main wrapper; renaming main to something custom; scripts where a comment or string between `def` and `main` resets the LastToken state.
Related errors
- Parsing error `:` should be before `=` it likely means you a
- Internal error, cannot check if argument is optional
- Rest (...) parameters are not supported
- Flags are not supported
- typed records are not supported, use `ident: record`
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/4964de3e1089588d.
Report an issue: GitHub.