infiniflow/ragflow · error · RuntimeError

Failed to create remote workspace on {self.host}: {stderr or

Error message

Failed to create remote workspace on {self.host}: {stderr or stdout or 'unknown error'}

What it means

Raised as RuntimeError by SSHProvider._create_remote_workspace when the remote command 'mkdir -p <work_dir> && mktemp -d <work_dir>/ragflow-codeexec.XXXXXX' exits non-zero. This runs during instance creation and per-execution workspace setup; the message includes the host and the remote stdout/stderr. It signals the SSH session works but the remote filesystem rejects the workspace creation.

Source

Thrown at agent/sandbox/providers/ssh.py:525

        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(
        self,
        sftp: paramiko.SFTPClient,
        remote_work_dir: str,
        language: str,
        code: str,
        args_json: str,
    ) -> tuple[str, str]:
        if language == "python":
            script_name = "main.py"
            script_content = build_python_wrapper(code, args_json)
        elif language in {"javascript", "nodejs"}:

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Set work_dir to a directory the SSH user can write (default /tmp) — check with ssh user@host 'touch /tmp/x && rm /tmp/x'
  2. Fix remote permissions: install -d -o <sshuser> <work_dir> on the host
  3. Free disk space / raise the tmpfs size if mktemp failed on ENOSPC
  4. Check the stderr fragment embedded in the message — it carries the exact remote error

Example fix

# before
provider.initialize({..., "work_dir": "/var/lib/ragflow/work"})  # not writable by ssh user

# after
provider.initialize({..., "work_dir": "/tmp"})
Defensive patterns

Strategy: validation

Validate before calling

import subprocess
work_dir = config.get("work_dir", "/tmp")
rc = subprocess.run(
    ["ssh", f"{config['username']}@{config['host']}", f"mkdir -p {work_dir} && mktemp -d {work_dir}/x.XXXXXX"]
).returncode
if rc != 0:
    raise RuntimeError(f"SSH user cannot create workspace under {work_dir}")

Try / catch

try:
    provider.create_instance(language="python")
except RuntimeError as e:
    if "Failed to create remote workspace" in str(e):
        raise RuntimeError(f"fix permissions on work_dir; remote said: {e}") from e

Prevention

When it happens

Trigger: work_dir config pointing to a directory the SSH user cannot create/write (permission denied); work_dir on a read-only filesystem; disk full (mktemp fails); SELinux/AppArmor denial; path with a non-directory component (e.g. /tmp/file/x).

Common situations: Setting work_dir to /var/lib/app owned by root while connecting as a non-root user; containers with read-only root filesystems where work_dir defaults under /tmp but tmpfs is size-limited; shared hosts with strict quotas.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/583e9b42fb093afa. Report an issue: GitHub.