n8n-io/n8n · critical · ValueError

Failed to read {env_name}_FILE from file {file_path}: {e}

Error message

Failed to read {env_name}_FILE from file {file_path}: {e}

What it means

Thrown by read_env in the Python task runner when an environment variable's _FILE companion is set but the file it points to cannot be read. The _FILE convention allows secrets to be injected from files (e.g. Docker secrets) rather than plaintext environment variables; read_env tries to read the file when the primary variable is absent, and wraps OSError/IOError in a ValueError with context.

Source

Thrown at packages/@n8n/task-runner-python/src/env.py:15

import os
from pathlib import Path


def read_env(env_name: str) -> str | None:
    if env_name in os.environ:
        return os.environ[env_name]

    file_path_key = f"{env_name}_FILE"
    if file_path_key in os.environ:
        file_path = os.environ[file_path_key]
        try:
            return Path(file_path).read_text(encoding="utf-8").strip()
        except (OSError, IOError) as e:
            raise ValueError(
                f"Failed to read {env_name}_FILE from file {file_path}: {e}"
            )

    return None


def read_str_env(env_name: str, default: str) -> str:
    value = read_env(env_name)
    if value is None:
        return default
    return value


def read_int_env(env_name: str, default: int) -> int:
    value = read_env(env_name)
    if value is None:
        return default
    try:

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Verify the file path in the _FILE environment variable exists and is readable by the runner process.
  2. Check file permissions: the runner user must have read access.
  3. Ensure Docker/Kubernetes secrets are mounted before the runner starts (use init containers or proper ordering).
  4. If the file is not needed, unset the _FILE variable and provide the value directly in the primary variable.

Example fix

# before — file doesn't exist
export N8N_RUNNERS_GRANT_TOKEN_FILE=/run/secrets/nonexistent
# after — create the secret or fix the path
docker secret create grant_token ./grant_token.txt
export N8N_RUNNERS_GRANT_TOKEN_FILE=/run/secrets/grant_token
Defensive patterns

Strategy: try-catch

Validate before calling

from pathlib import Path
import os

def read_env_file(env_name: str) -> str | None:
    file_key = f'{env_name}_FILE'
    if file_key in os.environ:
        path = Path(os.environ[file_key])
        if not path.exists():
            raise FileNotFoundError(f'{file_key} points to non-existent file: {path}')
        if not os.access(path, os.R_OK):
            raise PermissionError(f'Cannot read {file_key}: {path}')
        return path.read_text(encoding='utf-8').strip()
    return None

Try / catch

from env import read_env

try:
    token = read_env('N8N_RUNNERS_GRANT_TOKEN')
except ValueError as e:
    print(f'Failed to read secret file: {e}')
    sys.exit(1)

Prevention

When it happens

Trigger: The primary environment variable (e.g. N8N_RUNNERS_GRANT_TOKEN) is unset, but the _FILE variant (e.g. N8N_RUNNERS_GRANT_TOKEN_FILE) is set and points to a path that doesn't exist, is not readable, or has wrong permissions. Path(file_path).read_text() raises OSError or IOError, which is caught and re-raised as ValueError.

Common situations: Docker secret or Kubernetes secret mount path is wrong or the secret hasn't been created yet. File permissions don't allow the runner process to read the file. The _FILE path points to a directory instead of a file. Race condition where the runner starts before the secret file is mounted.

Related errors


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