infiniflow/ragflow · critical · SandboxProviderConfigError
Failed to load SSH private key. {errors}
Error message
Failed to load SSH private key. {errors} What it means
Raised as SandboxProviderConfigError by the private-key loader after every paramiko key class (RSAKey, Ed25519Key, ECDSAKey, etc.) failed to parse the configured private_key material. The message joins the individual per-loader errors, which distinguish wrong passphrase ('Private key file is encrypted' / decrypt errors) from wrong format ('not a valid OPENSSH or PEM key'). Both a file path and an in-memory key string are attempted depending on how the config was supplied.
Source
Thrown at agent/sandbox/providers/ssh.py:514
)
errors: list[str] = []
private_key_value = self.private_key.strip()
passphrase = self.passphrase or None
if os.path.exists(private_key_value):
for key_cls in loaders:
try:
return key_cls.from_private_key_file(private_key_value, password=passphrase)
except Exception as exc:
errors.append(str(exc))
else:
for key_cls in loaders:
try:
return key_cls.from_private_key(io.StringIO(private_key_value), password=passphrase)
except Exception as exc:
errors.append(str(exc))
raise SandboxProviderConfigError("Failed to load SSH private key. " + "; ".join(error for error in errors if error))
def _create_remote_workspace(self, client: paramiko.SSHClient) -> str:
base_dir = self.work_dir.rstrip("/") or "/tmp"
template = posixpath.join(base_dir, "ragflow-codeexec.XXXXXX")
stdout, stderr, exit_code = self._run_remote_command(
client,
f"mkdir -p {shlex.quote(base_dir)} && mktemp -d {shlex.quote(template)}",
timeout=min(self.timeout, 10),
)
if exit_code != 0:
raise RuntimeError(f"Failed to create remote workspace on {self.host}: {stderr or stdout or 'unknown error'}")
remote_work_dir = stdout.strip().splitlines()[-1] if stdout.strip() else ""
if not remote_work_dir:
raise RuntimeError("Remote workspace creation did not return a path.")
return remote_work_dir
def _upload_script(View on GitHub (pinned to 554fb1133a)
Solutions
- Read the joined per-key errors in the message: 'encrypted' means passphrase problem, 'invalid key' means format problem
- Verify the key locally: ssh-keygen -y -f <keyfile> (prompts for passphrase) or chmod 400 + ssh -i
- If newlines were flattened in config, re-supply the key as a file path instead of an inline string
- For unsupported formats: convert with ssh-keygen -p -m PEM -f <key> (or -t ed25519 to regenerate), or upgrade paramiko
Example fix
# before: inline key with escaped newlines from a secret
provider.initialize({..., "private_key": "-----BEGIN...-----BEGIN OPENSSH...\nAAA..."})
# after: pass a real file path
provider.initialize({..., "private_key": "/secrets/id_ed25519", "passphrase": "correct-horse"}) Defensive patterns
Strategy: validation
Validate before calling
import os
key = config.get("private_key", "")
if key and not os.path.isfile(key) and "PRIVATE KEY" not in key:
raise RuntimeError("private_key must be a readable file path or a PEM/OpenSSH key body") Try / catch
try:
provider.initialize(config)
except SandboxProviderConfigError as e:
if "Failed to load SSH private key" in str(e):
# message joins per-loader errors: 'encrypted' => passphrase, else format
log.error("key load failed: %s", e) Prevention
- Prefer file paths for keys over inline strings to avoid newline escaping issues in secrets
- Validate keys at deploy time with ssh-keygen -y -f <key>
- Keep paramiko current so modern OpenSSH key formats parse
When it happens
Trigger: initialize() with a private_key value that is neither a readable path nor a valid PEM/OpenSSH key body; correct key but wrong passphrase; key in a format paramiko's version does not support (e.g. very new OpenSSH format on an old paramiko); key body truncated or with escaped newlines mangled by config transport.
Common situations: Passing a Docker/K8s secret with literal '\n' instead of real newlines; PuTTYgen .ppk keys (unsupported by paramiko); passphrase mismatch after key rotation; ancient paramiko that cannot read openssh-key v1 format Ed25519 keys.
Related errors
- Failed to connect to SSH host {self.username}@{self.host}:{s
- Failed to update memory
- Invalid SSH provider configuration.
- SSH connectivity check failed on {self.username}@{self.host}
- Failed to load configured SSH known_hosts file.
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/d2b3d3f610ddb208.
Report an issue: GitHub.