{"record":{"id":"e4509cd3ddff4e69","repo":"windmill-labs/windmill","slug":"no-workflow-function-found-in-script","errorCode":null,"errorMessage":"No @workflow function found in script","messagePattern":"No @workflow function found in script","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/windmill-worker/src/python_executor.rs","lineNumber":900,"sourceCode":"    checkpoint = json.load(f, strict=False)\n\nresult_json = os.path.join(os.path.abspath(os.path.dirname(__file__)), \"result.json\")\n\ntry:\n    {wac_preprocessor}\n    args = kwargs\n    for k, v in list(args.items()):\n        if v == '<function call>':\n            del args[k]\n\n    workflow_fn = None\n    for name in dir(inner_script):\n        obj = getattr(inner_script, name)\n        if callable(obj) and getattr(obj, '_is_workflow', False):\n            workflow_fn = obj\n            break\n    if workflow_fn is None:\n        raise ValueError(\"No @workflow function found in script\")\n\n    output = _run_workflow(workflow_fn, checkpoint, args)\n    if isinstance(output, dict) and output.get(\"type\") == \"complete\":\n        print(\"\")\n        print(\"--- WAC: complete ---\")\n    output_json = json.dumps(output, separators=(',', ':'), default=str)\n    with open(result_json, 'w') as f:\n        f.write(output_json)\nexcept BaseException as e:\n    exc_type, exc_value, exc_traceback = sys.exc_info()\n    tb = traceback.format_tb(exc_traceback)\n    with open(result_json, 'w') as f:\n        err = {{ \"message\": str(e), \"name\": e.__class__.__name__, \"stack\": '\\n'.join(tb[1:]) }}\n        extra = e.__dict__\n        if extra and len(extra) > 0:\n            err['extra'] = extra\n        flow_node_id = os.environ.get('WM_FLOW_STEP_ID')\n        if flow_node_id:","sourceCodeStart":882,"sourceCodeEnd":918,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-worker/src/python_executor.rs#L882-L918","documentation":"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.","triggerScenarios":"Thrown at backend/windmill-worker/src/python_executor.rs:900 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"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"}