windmill-labs/windmill · error · Error

${main_name} function is missing

Error message

${main_name} function is missing

What it means

Thrown from the generated `run()` wrapper when the script's main entrypoint (named by main_name, typically `main`) is undefined or not a function. The worker builds a wrapper that calls `{main_name}(...argsArr)`, and guards it so that a script without the expected exported entry function fails with a clear message instead of a confusing 'undefined is not a function' TypeError.

Source

Thrown at backend/windmill-worker/src/deno_executor.rs:355

function argsObjToArr({{ {spread} }}) {{
    return [ {spread} ];
}}

BigInt.prototype.toJSON = function () {{
    return this.toString();
}};

function isAsyncIterable(obj) {{
    return obj != null && typeof obj[Symbol.asyncIterator] === 'function';
}}

async function run() {{
    {dates}
    {preprocessor}
    const argsArr = argsObjToArr(args);
    if ({main_name} === undefined || typeof {main_name} !== 'function') {{
        throw new Error("{main_name} function is missing");
    }}
    let res: any = await {main_name}(...argsArr);
    if (isAsyncIterable(res)) {{
        for await (const chunk of res) {{
            console.log("WM_STREAM: " + chunk.replace(/\n/g, '\\n'));
        }}
        res = null;
    }}
    const res_json = JSON.stringify(res ?? null, (key, value) => typeof value === 'undefined' ? null : value);
    await Deno.writeTextFile("result.json", res_json);
    Deno.exit(0);
}}
try {{
    await run();
}} catch(e) {{
    let err = {{ message: e.message, name: e.name, stack: e.stack }};
    let step_id = Deno.env.get("WM_FLOW_STEP_ID");
    if (step_id) {{

View on GitHub (pinned to e474e8803c)

Solutions

  1. Export a function named `main` from the script: `export async function main(args) { ... }`
  2. Check the script's entrypoint setting (advanced options) matches the exported function name if you intentionally use a different name
  3. Add the missing `export` keyword — `function main()` alone is not visible to the wrapper
  4. Ensure the script was saved/deployed so the running version actually contains the export

Example fix

// before
async function main(x: number) {
  return x * 2;
} // not exported
// after
export async function main(x: number) {
  return x * 2;
}
Defensive patterns

Strategy: validation

Validate before calling

// guard in the script file itself:
if (typeof main !== 'function') {
  throw new Error('script must export a `main` function');
}

Type guard

function hasMain(mod: Record<string, unknown>): mod is { main: (...args: unknown[]) => unknown } {
  return typeof mod.main === 'function';
}

Prevention

When it happens

Trigger: Executing any Deno/TypeScript script whose source does not export a function with the configured entrypoint name (usually `main`) — e.g. no export at all, `export function Main()` with different casing, or the export is a non-callable value.

Common situations: New script created from an empty template without a `main` export; renaming `main` to something else while the script metadata still points to `main`; forgetting the `export` keyword; writing `main` as a top-level side-effect script with no function; language/entrypoint mismatch after switching script kind.

Related errors


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