infiniflow/ragflow · error · RuntimeError

Failed to create remote artifacts directory: {stderr or stdo

Error message

Failed to create remote artifacts directory: {stderr or stdout or 'unknown error'}

What it means

Raised by SSHProvider.create_instance() when the remote command 'mkdir -p <work_dir>/artifacts' returns a non-zero exit code over the SSH channel. The message embeds the remote stderr (or stdout) so the remote shell's actual complaint is visible. On failure the freshly opened SSH client and SFTP session are closed and the exception propagates; no instance is registered.

Source

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

        return True

    def create_instance(self, template: str = "python") -> SandboxInstance:
        if not self._initialized:
            raise RuntimeError("Provider not initialized. Call initialize() first.")

        language = self._normalize_language(template)
        client = self._create_ssh_client()
        sftp = client.open_sftp()

        try:
            remote_work_dir = self._create_remote_workspace(client)
            stdout, stderr, exit_code = self._run_remote_command(
                client,
                f"mkdir -p {shlex.quote(posixpath.join(remote_work_dir, 'artifacts'))}",
                timeout=min(self.timeout, 10),
            )
            if exit_code != 0:
                raise RuntimeError(f"Failed to create remote artifacts directory: {stderr or stdout or 'unknown error'}")
        except Exception:
            sftp.close()
            client.close()
            raise

        instance_id = str(uuid.uuid4())
        self._instances[instance_id] = {
            "client": client,
            "sftp": sftp,
            "remote_work_dir": remote_work_dir,
            "language": language,
        }

        return SandboxInstance(
            instance_id=instance_id,
            provider="ssh",
            status="running",
            metadata={"language": language, "remote_work_dir": remote_work_dir},

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Read the embedded stderr — it names the exact OS-level failure (Permission denied, Read-only file system, No space left on device, Not a directory).
  2. Set 'work_dir' to a location the SSH user can write, e.g. /tmp/ragflow-sandbox or the user's home, in the initialize() config.
  3. Fix the remote side: ensure the parent path exists and is writable, remove a conflicting regular file at that path, free disk space.
  4. Verify manually first: ssh user@host 'mkdir -p <work_dir>/artifacts' should succeed before re-running.

Example fix

# before
provider.initialize({..., "work_dir": "/var/lib/sandbox"})  # not writable

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

Strategy: validation

Validate before calling

# preflight the exact command the provider runs, over the same credentials:
import subprocess
rc = subprocess.call(["ssh", f"{user}@{host}", f"mkdir -p {work_dir}/artifacts"])
assert rc == 0, "remote artifacts dir not creatable"

Try / catch

try:
    instance = provider.create_instance("python")
except RuntimeError as e:
    if "Failed to create remote artifacts directory" in str(e):
        # stderr inside the message names the OS cause: permissions / read-only / no space
        raise SandboxWorkspaceError(str(e)) from e
    raise

Prevention

When it happens

Trigger: work_dir pointing at a path the SSH user cannot create (permission denied, e.g. /root as non-root); work_dir on a read-only filesystem; disk full on the remote host; work_dir containing a component that is a regular file (mkdir fails with 'File exists' for a non-directory); SELinux/AppArmor denials.

Common situations: Default work_dir '/tmp' replaced with a restricted path; SSH user chrooted or scoped with limited commands; a stale file occupying the intended directory path; remote host out of inode space.

Related errors


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