{"record":{"id":"4da75b1666f1e294","repo":"n8n-io/n8n","slug":"task-execution-timed-out-after-task-timeout-seco","errorCode":null,"errorMessage":"Task execution timed out after {task_timeout} seconds","messagePattern":"Task execution timed out after (.+?) seconds","errorType":"exception","errorClass":"TaskTimeoutError","httpStatus":null,"severity":"error","filePath":"packages/@n8n/task-runner-python/src/task_executor.py","lineNumber":231,"sourceCode":"\n        print_args: PrintArgs = []\n\n        pipe_reader = PipeReader(read_conn.fileno(), read_conn)\n        pipe_reader.start()\n\n        try:\n            try:\n                process.start()\n            except Exception as e:\n                raise TaskSubprocessFailedError(-1, e)\n            finally:\n                write_conn.close()\n\n            process.join(timeout=task_timeout)\n\n            if process.is_alive():\n                TaskExecutor.stop_process(process)\n                raise TaskTimeoutError(task_timeout)\n\n            if process.exitcode == SIGTERM_EXIT_CODE:\n                raise TaskCancelledError()\n\n            if process.exitcode == SIGKILL_EXIT_CODE:\n                raise TaskKilledError()\n\n            if process.exitcode != 0:\n                assert process.exitcode is not None\n                raise TaskSubprocessFailedError(process.exitcode)\n\n            pipe_reader.join(timeout=task_timeout)\n\n            if pipe_reader.is_alive():\n                try:\n                    read_conn.close()\n                except Exception:\n                    pass","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/task-runner-python/src/task_executor.py#L213-L249","documentation":"TaskTimeoutError is raised by TaskExecutor.execute_process when the forked Python subprocess is still alive after process.join(timeout=task_timeout) returns. The executor first attempts graceful termination via stop_process before raising, so by the time the error surfaces the child has already been signaled to stop. The {task_timeout} placeholder is the per-task ceiling (seconds) configured on the task runner.","triggerScenarios":"A Python code task whose top-level execution (the forked process running the user's code) does not return within the configured task_timeout. Triggered by an infinite loop, a long sleep, a blocking socket read with no timeout, or a runaway computation in the user's Python snippet.","commonSituations":"User code calls time.sleep(very_large_number), runs a tight while True loop, performs a synchronous requests.get against a slow endpoint without a timeout, or processes a huge dataset in one shot. Also occurs when the runner is deployed on a CPU-constrained node and the default task_timeout is too low for legitimate work.","solutions":["Inspect the Python snippet for loops, sleeps, or blocking I/O and add internal progress checks or shorter timeouts so the task finishes well under task_timeout.","If the work is legitimately long, raise the task_timeout configuration for the task runner (e.g. TASK_RUNNER_TASK_TIMEOUT env / config) to a value with headroom above the worst observed run.","Replace blocking calls (requests, input, socket reads) with timeout-bounded equivalents (requests.get(url, timeout=...), selectors) so the task fails fast instead of hanging until the ceiling.","For CPU-bound work, move heavy processing into a worker pool with chunked progress reporting so partial results can be emitted before the ceiling."],"exampleFix":"// before\nimport time\nwhile True:\n    do_work()\n// after\nimport time\ndeadline = time.monotonic() + (task_timeout_seconds - 5)\nwhile time.monotonic() < deadline:\n    do_work()\n","handlingStrategy":"try-catch","validationCode":"# No pre-check possible; instead bound work internally.\nimport time\ndef run_with_budget(fn, budget_seconds):\n    deadline = time.monotonic() + budget_seconds\n    while time.monotonic() < deadline:\n        if not fn.step():\n            break\n    return fn.result()\n","typeGuard":null,"tryCatchPattern":"from n8n_task_runner.errors import TaskTimeoutError\ntry:\n    result = TaskExecutor.execute_process(proc, rc, wc, task_timeout, continue_on_fail=False)\nexcept TaskTimeoutError as e:\n    # task exceeded ceiling; surface a cancellation-style result\n    return [{\"json\": {\"error\": f\"task timed out: {e}\"}}], [], 0\n","preventionTips":["Always pass an explicit task_timeout sized to the worst-case legitimate run plus headroom.","For network calls inside user code, always set client-side timeouts smaller than task_timeout.","Prefer continue_on_fail=True for non-critical tasks so a single timeout does not abort the workflow.","Log task wall-clock times to detect slow drift before it hits the ceiling."],"tags":["python","task-runner","timeout","subprocess","concurrency"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}