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
- Check the chained exception (the second argument to TaskSubprocessFailedError) for the root cause — it contains the original error from process.start().
- Verify the Python environment is intact: correct Python version, required packages installed, no import errors in the target module.
- Check system resource limits: max processes (ulimit -u), available memory, file descriptor limits.
- If the forkserver is in a bad state, restart the runner process to get a fresh multiprocessing context.
- 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
- Monitor runner process health and restart on crash.
- Verify the Python environment and all dependencies are installed before starting the runner.
- Set appropriate resource limits (ulimit) to prevent fork failures.
- Log chained exceptions to capture the root cause of subprocess start failures.
- Use a process manager (systemd, supervisor) to auto-restart the runner on failure.
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
- Task execution timed out after {task_timeout} seconds
- Task was cancelled
- Process was forcefully killed (SIGKILL)
- Task subprocess exited with code {exit_code}
- Security violation detected
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/0519865e2dc469b9.
Report an issue: GitHub.