n8n-io/n8n · critical · TaskSubprocessFailedError

Task subprocess exited with code -1

Error message

Task subprocess exited with code -1

What it means

Thrown by TaskExecutor.execute_process when process.start() raises an exception, indicating the Python subprocess for a code task could not be launched at all. The exit code is set to -1 (a sentinel, not a real OS exit code) and the original exception is chained. This is distinct from a subprocess that starts but then crashes (which would have a real exit code).

Source

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

    def execute_process(
        process: ForkServerProcess,
        read_conn: PipeConnection,
        write_conn: PipeConnection,
        task_timeout: int,
        continue_on_fail: bool,
    ) -> tuple[Items, PrintArgs, int]:
        """Execute a subprocess for a Python code task."""

        print_args: PrintArgs = []

        pipe_reader = PipeReader(read_conn.fileno(), read_conn)
        pipe_reader.start()

        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)

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Check the chained exception (the second argument to TaskSubprocessFailedError) for the root cause — it contains the original error from process.start().
  2. Verify the Python environment is intact: correct Python version, required packages installed, no import errors in the target module.
  3. Check system resource limits: max processes (ulimit -u), available memory, file descriptor limits.
  4. If the forkserver is in a bad state, restart the runner process to get a fresh multiprocessing context.
  5. Look at runner logs for earlier errors that may have corrupted the forkserver state.

Example fix

# This is an infrastructure error, not a code fix.
# Check the chained exception for root cause:

# In runner logs, look for:
# TaskSubprocessFailedError: Task subprocess exited with code -1
# Caused by: <original exception from process.start()>

# Common fixes:
# 1. Restart the runner: kill the runner process and let n8n respawn it
# 2. Check Python environment: python3 -c 'import task_executor'
# 3. Check resource limits: ulimit -a
# 4. Verify no missing shared libraries: ldd $(which python3)
Defensive patterns

Strategy: try-catch

Validate before calling

import sys, importlib

def verify_runner_environment() -> bool:
    """Check that the subprocess can import its target."""
    try:
        importlib.import_module('task_executor')
        return True
    except ImportError as e:
        print(f'Runner environment broken: {e}')
        return False

if not verify_runner_environment():
    sys.exit(1)

Try / catch

from task_executor import TaskSubprocessFailedError, TaskTimeoutError, TaskCancelledError

try:
    items, print_args, exit_code = TaskExecutor.execute_process(
        process, read_conn, write_conn, task_timeout, continue_on_fail
    )
except TaskSubprocessFailedError as e:
    if e.exit_code == -1:
        logger.critical('Subprocess failed to start', exc_info=e.original)
        # restart the runner or fall back to internal execution
    else:
        logger.error(f'Subprocess exited with code {e.exit_code}')

Prevention

When it happens

Trigger: The multiprocessing forkserver process fails to start. Common causes include the forkserver context being unavailable, the target function failing to import, the Pipe being broken before start(), or OS-level resource limits preventing process creation. The try/except around process.start() catches any Exception and wraps it in TaskSubprocessFailedError(-1, e).

Common situations: The Python runtime or required modules are missing or misconfigured in the subprocess environment. Resource exhaustion (too many processes, out of memory) preventing fork/spawn. The forkserver process crashed and cannot accept new processes. A broken pipe or serialization error when the runner tries to pass items to the subprocess. Incompatible Python version or missing shared libraries.

Related errors


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