n8n-io/n8n · critical · TaskKilledError

Process was forcefully killed (SIGKILL)

Error message

Process was forcefully killed (SIGKILL)

What it means

TaskKilledError is raised when the forked subprocess exited with SIGKILL_EXIT_CODE. SIGKILL cannot be caught, so this always means the OS or the runner's stop_process escalation overrode the process. It indicates the process did not honor an earlier SIGTERM within the grace window, or the OS killed it directly (OOM killer).

Source

Thrown at packages/@n8n/task-runner-python/src/task_executor.py:237

        try:
            try:
                process.start()
            except Exception as e:
                raise TaskSubprocessFailedError(-1, e)
            finally:
                write_conn.close()

            process.join(timeout=task_timeout)

            if process.is_alive():
                TaskExecutor.stop_process(process)
                raise TaskTimeoutError(task_timeout)

            if process.exitcode == SIGTERM_EXIT_CODE:
                raise TaskCancelledError()

            if process.exitcode == SIGKILL_EXIT_CODE:
                raise TaskKilledError()

            if process.exitcode != 0:
                assert process.exitcode is not None
                raise TaskSubprocessFailedError(process.exitcode)

            pipe_reader.join(timeout=task_timeout)

            if pipe_reader.is_alive():
                try:
                    read_conn.close()
                except Exception:
                    pass
                raise TaskResultReadError(
                    TimeoutError(f"Pipe reader timed out after {task_timeout}s")
                )

            if pipe_reader.error:
                raise TaskResultReadError(pipe_reader.error)

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Check runner/container memory limits and either raise the limit or reduce the working-set size in user code (stream instead of load-all, free intermediate buffers, use generators).
  2. Ensure user code does not install a SIGTERM handler that prevents shutdown; if it must handle SIGTERM, exit promptly rather than continuing.
  3. If using stop_process, confirm the grace window is shorter than task_timeout so SIGKILL only happens after a genuine hang, not a slow-but-progressing task.
  4. Inspect dmesg / kernel logs for OOM-kill entries on the task PID to distinguish runner-initiated kill from OS-initiated kill.

Example fix

// before
import pandas as pd
df = pd.read_csv('huge.csv')  # loads entire file, OOM risk
// after
import pandas as pd
for chunk in pd.read_csv('huge.csv', chunksize=10000):
    process(chunk)
Defensive patterns

Strategy: try-catch

Try / catch

from n8n_task_runner.errors import TaskKilledError
try:
    result = TaskExecutor.execute_process(proc, rc, wc, task_timeout, continue_on_fail=False)
except TaskKilledError:
    # likely OOM or unresponsive child; report and surface diagnostics
    return [{"json": {"error": "task force-killed (possible OOM)"}}], [], 0

Prevention

When it happens

Trigger: stop_process escalated from SIGTERM to SIGKILL after the grace period because the child was unresponsive; or the kernel OOM killer selected the child because it exceeded the cgroup/host memory limit; or an external kill -9 was sent to the PID.

Common situations: User Python code allocates a large list/dataframe and hits the container memory limit; user code catches SIGTERM and ignores it (or is stuck in a C extension that can't be interrupted); the host is under memory pressure and the OOM killer reaps the task process.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/2bb5eb5285d1b693. Report an issue: GitHub.