windmill-labs/windmill · error · ValueError
No @workflow function found in script
Error message
No @workflow function found in script
What it means
Raised as a Python ValueError inside the workflow-as-code runner injected by handle_python_job: after loading the user's inner script as a module, the runner scans it for a callable tagged `_is_workflow` (set by the @workflow decorator) and none exists, so there is no entry point to execute. It fires inside the sandboxed wrapper at job run time.
Source
Thrown at backend/windmill-worker/src/python_executor.rs:900
checkpoint = json.load(f, strict=False)
result_json = os.path.join(os.path.abspath(os.path.dirname(__file__)), "result.json")
try:
{wac_preprocessor}
args = kwargs
for k, v in list(args.items()):
if v == '<function call>':
del args[k]
workflow_fn = None
for name in dir(inner_script):
obj = getattr(inner_script, name)
if callable(obj) and getattr(obj, '_is_workflow', False):
workflow_fn = obj
break
if workflow_fn is None:
raise ValueError("No @workflow function found in script")
output = _run_workflow(workflow_fn, checkpoint, args)
if isinstance(output, dict) and output.get("type") == "complete":
print("")
print("--- WAC: complete ---")
output_json = json.dumps(output, separators=(',', ':'), default=str)
with open(result_json, 'w') as f:
f.write(output_json)
except BaseException as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
tb = traceback.format_tb(exc_traceback)
with open(result_json, 'w') as f:
err = {{ "message": str(e), "name": e.__class__.__name__, "stack": '\n'.join(tb[1:]) }}
extra = e.__dict__
if extra and len(extra) > 0:
err['extra'] = extra
flow_node_id = os.environ.get('WM_FLOW_STEP_ID')
if flow_node_id:View on GitHub (pinned to e474e8803c)
Solutions
- Decorate the entry function with @workflow so the runner can find it
- Ensure the decorated function is defined at module top level, not nested or conditionally defined
- Check that no typo in the decorator import silently left the marker unset
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at backend/windmill-worker/src/python_executor.rs:900 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/e4509cd3ddff4e69.
Report an issue: GitHub.