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
- Verify the file path in the _FILE environment variable exists and is readable by the runner process.
- Check file permissions: the runner user must have read access.
- Ensure Docker/Kubernetes secrets are mounted before the runner starts (use init containers or proper ordering).
- 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
- Verify _FILE paths exist and are readable before starting the runner.
- Use Docker/Kubernetes health checks to verify secret mounts before the container starts.
- Ensure file permissions allow the runner process to read secret files.
- Prefer the _FILE convention for secrets to avoid leaking them in environment variables.
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
- Environment variable N8N_RUNNERS_GRANT_TOKEN is required
- Task timeout must be positive, got {task_timeout}
- Auto shutdown timeout must be non-negative, got {auto_shutdo
- Graceful shutdown timeout must be positive, got {graceful_sh
- Max payload size of {max_payload_size} bytes exceeds pipe me
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/ba580cb759c31c8b.
Report an issue: GitHub.