infiniflow/ragflow · warning · RuntimeError

Unsupported artifact type: {relative_path}

Error message

Unsupported artifact type: {relative_path}

What it means

Raised as RuntimeError when an artifact's file extension is not in ALLOWED_ARTIFACT_EXTENSIONS ({.csv,.html,.jpeg,.jpg,.json,.pdf,.png,.svg}). The whitelist bounds what content types get base64-embedded and returned to the agent, blocking arbitrary binary types. It fires after the regular-file, symlink, count, and size checks pass, so a file failing here was otherwise collectable.

Source

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

            if stat.S_ISLNK(mode):
                raise RuntimeError(f"Artifact symlinks are not allowed: {relative_path}")
            if stat.S_ISDIR(mode):
                self._collect_artifacts_recursive(sftp, remote_path, relative_path, artifacts)
                continue
            if not stat.S_ISREG(mode):
                raise RuntimeError(f"Unsupported artifact entry: {relative_path}")

            if len(artifacts) >= self.max_artifacts:
                raise RuntimeError(f"SSH execution produced more than {self.max_artifacts} artifacts.")

            size = int(entry.st_size or 0)
            if size > self.max_artifact_bytes:
                raise RuntimeError(f"Artifact exceeds {self.max_artifact_bytes} bytes: {relative_path}")

            ext = os.path.splitext(name)[1].lower()
            if ext not in ALLOWED_ARTIFACT_EXTENSIONS:
                raise RuntimeError(f"Unsupported artifact type: {relative_path}")

            with sftp.file(remote_path, "rb") as artifact_file:
                content = artifact_file.read()

            artifacts.append(
                {
                    "name": relative_path,
                    "content_b64": base64.b64encode(content).decode("ascii"),
                    "mime_type": mimetypes.guess_type(name)[0] or "application/octet-stream",
                    "size": size,
                }
            )

    @staticmethod
    def _normalize_language(language: str) -> str:
        lang_lower = (language or "python").lower()
        if lang_lower in {"python", "python3"}:
            return "python"

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Emit only whitelisted types: wrap text in .html/.json/.csv, re-encode spreadsheets as CSV, export charts as .png/.svg
  2. Delete non-whitelisted intermediates before the sandboxed code returns
  3. Rename to a truthful allowed extension only when content genuinely matches (e.g. JSON data -> .json)

Example fix

# before (sandboxed code)
open('artifacts/notes.txt', 'w').write('ok')

# after (sandboxed code)
import json
json.dump({'note': 'ok'}, open('artifacts/notes.json', 'w'))
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = {".csv", ".html", ".jpeg", ".jpg", ".json", ".pdf", ".png", ".svg"}
import os
bad = [f for f in os.listdir(artifacts_dir) if os.path.splitext(f)[1].lower() not in ALLOWED]
if bad:
    raise RuntimeError(f"non-whitelisted artifact extensions: {bad}")

Type guard

ALLOWED = {".csv", ".html", ".jpeg", ".jpg", ".json", ".pdf", ".png", ".svg"}
def is_allowed_artifact_name(name: str) -> bool:
    return os.path.splitext(name)[1].lower() in ALLOWED

Try / catch

try:
    artifacts = provider.collect_artifacts(instance_id, artifacts_dir)
except RuntimeError as e:
    if "Unsupported artifact type" in str(e):
        raise RuntimeError("rename/re-encode outputs to a whitelisted type: csv/html/jpg/json/pdf/png/svg") from e

Prevention

When it happens

Trigger: Sandboxed code writing .txt, .xlsx, .xml, .parquet, .zip, or extensionless files into the artifacts dir; uppercase extensions are fine (lowercased before check) but e.g. '.JSON5' or '.htm' are not; generated temp files like 'plot.png.tmp' left behind.

Common situations: Excel exports (.xlsx) from data code; plain-text logs; intermediate files not cleaned up; users expecting .txt to be allowed.

Related errors


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