infiniflow/ragflow · error · SandboxProviderConfigError
Failed to load configured SSH known_hosts file.
Error message
Failed to load configured SSH known_hosts file.
What it means
Raised as SandboxProviderConfigError when the operator configured a known_hosts file (self.known_hosts) but client.load_host_keys() raised OSError — file missing, unreadable, or a directory. The provider deliberately fails closed: continuing with only system keys could let the connection trust an unintended anchor (e.g. an attacker-writable ~/.ssh/known_hosts), matching the Go provider's posture. The OSError is chained and a warning is logged.
Source
Thrown at agent/sandbox/providers/ssh.py:464
# RejectPolicy would reject every host on first connect,
# breaking the provider for normal setups. The order matters:
# load_system_host_keys() populates the store from
# ~/.ssh/known_hosts (and the legacy /etc/ssh/ssh_known_hosts);
# an optional explicit known_hosts file from `known_hosts`
# config is then merged on top.
client.load_system_host_keys()
if self.known_hosts:
try:
client.load_host_keys(self.known_hosts)
except OSError as exc:
# Fail closed when the operator-configured trust store
# is unreadable: continuing with system keys could let
# the connection succeed against an unintended anchor
# (e.g. an attacker who can write ~/.ssh/known_hosts).
# Match the Go provider's fail-closed posture (see
# internal/agent/sandbox/ssh.go::hostKeyCallback).
logging.warning("SSH: failed to load configured known_hosts file; refusing connection")
raise SandboxProviderConfigError("Failed to load configured SSH known_hosts file.") from exc
# Reject unknown hosts: this is the default fail-closed posture
# to prevent silent MITM. Operators must either ship a populated
# known_hosts file or accept the warning (paramiko will fail the
# connect) on first encounter.
client.set_missing_host_key_policy(paramiko.RejectPolicy())
connect_kwargs: dict[str, Any] = {
"hostname": self.host,
"port": self.port,
"username": self.username,
"timeout": self.timeout,
"banner_timeout": self.timeout,
"auth_timeout": self.timeout,
"look_for_keys": False,
"allow_agent": False,
}
if self.private_key:
connect_kwargs["pkey"] = self._load_private_key()View on GitHub (pinned to 554fb1133a)
Solutions
- Verify the file exists and is readable by the service user: ls -l <known_hosts path>
- Create it if missing: ssh-keyscan -H <host> > <known_hosts> (run from a trusted network)
- Fix permissions/ownership: chown <service-user> <file> && chmod 644 <file>
- Or clear the known_hosts config option to rely on system host keys (still fail-closed via RejectPolicy)
Example fix
# before
provider.initialize({..., "known_hosts": "/etc/ragflow/known_hosts"}) # file absent -> fail closed
# after
ssh-keyscan -H 10.0.0.5 > /etc/ragflow/known_hosts && chmod 644 /etc/ragflow/known_hosts
provider.initialize({..., "known_hosts": "/etc/ragflow/known_hosts"}) Defensive patterns
Strategy: validation
Validate before calling
import os
kh = config.get("known_hosts", "")
if kh and not (os.path.isfile(kh) and os.access(kh, os.R_OK)):
raise RuntimeError(f"known_hosts path {kh!r} missing or unreadable; run ssh-keyscan first") Try / catch
try:
provider.initialize(config)
except SandboxProviderConfigError as e:
if "known_hosts" in str(e):
subprocess.run(f"ssh-keyscan -H {config['host']} > {config['known_hosts']}", shell=True, check=True)
provider.initialize(config) Prevention
- Generate the known_hosts file during deployment (ssh-keyscan) and verify readability by the service user
- Mount it read-only into containers with mode 644
- Fail CI/CD when the configured known_hosts path is absent instead of discovering it at runtime
When it happens
Trigger: initialize() with known_hosts pointing to a path that does not exist; file present but wrong ownership/permissions (OSError EACCES) especially when the app runs as a different user; path is a directory; container image built without copying the known_hosts file.
Common situations: Deploying with a config template referencing /etc/ssh/ssh_known_hosts that is absent in a slim container; file mounted read-only with restrictive mode; path typo or trailing whitespace in the config value (it is stripped, but case-sensitivity on paths still bites).
Related errors
- Failed to create remote workspace on {self.host}: {stderr or
- Invalid SSH provider configuration.
- SSH connectivity check failed on {self.username}@{self.host}
- Failed to connect to SSH host {self.username}@{self.host}:{s
- Failed to load SSH private key. {errors}
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/dcbe39e10b8215a0.
Report an issue: GitHub.