{"record":{"id":"4c65e7b3afb74f1b","repo":"infiniflow/ragflow","slug":"ucloud-agent-sandbox-execution-produced-more-than","errorCode":null,"errorMessage":"UCloud Agent Sandbox execution produced more than {self.max_artifacts} artifacts.","messagePattern":"UCloud Agent Sandbox execution produced more than (.+?) artifacts\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"agent/sandbox/providers/ucloud_agent_sandbox.py","lineNumber":431,"sourceCode":"    def _collect_artifacts_recursive(self, sandbox, current_dir: str, relative_dir: str, artifacts: list[dict[str, Any]], depth: int) -> None:\n        \"\"\"Traverse artifact directories while enforcing type, size, and depth limits.\"\"\"\n        if depth > MAX_ARTIFACT_DEPTH:\n            raise RuntimeError(f\"Artifact directory nesting exceeds {MAX_ARTIFACT_DEPTH} levels: {relative_dir}\")\n        sdk = _get_ucloud_sandbox_module()\n        try:\n            entries = sandbox.files.list(current_dir, depth=1, request_timeout=self.timeout)\n        except sdk.FileNotFoundException:\n            return\n        for entry in sorted(entries, key=lambda item: item.path):\n            name = posixpath.basename(entry.path)\n            relative_path = posixpath.join(relative_dir, name) if relative_dir else name\n            if entry.symlink_target is not None:\n                raise RuntimeError(f\"Artifact symlinks are not allowed: {relative_path}\")\n            if entry.type == sdk.FileType.DIR:\n                self._collect_artifacts_recursive(sandbox, entry.path, relative_path, artifacts, depth + 1)\n                continue\n            if len(artifacts) >= self.max_artifacts:\n                raise RuntimeError(f\"UCloud Agent Sandbox execution produced more than {self.max_artifacts} artifacts.\")\n            if entry.size > self.max_artifact_bytes:\n                raise RuntimeError(f\"Artifact exceeds {self.max_artifact_bytes} bytes: {relative_path}\")\n            extension = os.path.splitext(name)[1].lower()\n            if extension not in ALLOWED_ARTIFACT_EXTENSIONS:\n                raise RuntimeError(f\"Unsupported artifact type: {relative_path}\")\n            content = bytes(sandbox.files.read(entry.path, format=\"bytes\", request_timeout=self.timeout))\n            artifacts.append(\n                {\n                    \"name\": relative_path,\n                    \"content_b64\": base64.b64encode(content).decode(\"ascii\"),\n                    \"mime_type\": mimetypes.guess_type(name)[0] or \"application/octet-stream\",\n                    \"size\": entry.size,\n                }\n            )\n\n    def _safe_kill(self, sandbox) -> None:\n        \"\"\"Best-effort terminate a remote sandbox during cleanup.\"\"\"\n        try:","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/sandbox/providers/ucloud_agent_sandbox.py#L413-L449","documentation":"Raised during artifact collection when the number of collected files would exceed `max_artifacts` (default 20). The check is `len(artifacts) >= self.max_artifacts` before appending each new file, so the 21st default artifact (files are traversed in sorted order) triggers it, discarding the whole execution result.","triggerScenarios":"Executed code writing more than max_artifacts files into the artifacts directory — e.g. loops emitting per-item files, batch exports, or unpacked archives with many entries.","commonSituations":"Default cap of 20 too small for batch jobs writing one file per record; archive unpacking flooding the dir; users unaware that artifacts are meant to be a small curated set, not bulk storage.","solutions":["Write only the important outputs to artifacts; keep count at or under the cap (default 20).","Bundle many files into one artifact (zip/tar) — subject to extension and size policy.","Raise `max_artifacts` in the provider config for legitimate bulk-output workloads.","Catch the RuntimeError and report which execution over-produced artifacts."],"exampleFix":"# before\nfor i, item in enumerate(items):\n    open(f\"artifacts/item_{i}.json\", \"w\").write(...)  # 500 items -> RuntimeError\n\n# after\nimport json\nopen(\"artifacts/items.json\", \"w\").write(json.dumps(items))","handlingStrategy":"validation","validationCode":"max_artifacts = int(conf.get(\"max_artifacts\", 20))\n# when generating code, cap writes: emit one bundle instead of N files\nguided_code = (\n    \"import json\\n\"\n    f\"assert len(outputs) <= {max_artifacts}, 'too many artifacts'\\n\"\n    \"open('artifacts/outputs.json', 'w').write(json.dumps(outputs))\\n\"\n)","typeGuard":"def is_artifact_count_error(exc: RuntimeError) -> bool:\n    return \"more than\" in str(exc) and \"artifacts\" in str(exc)","tryCatchPattern":"try:\n    result = provider.execute(inst, code)\nexcept RuntimeError as e:\n    if \"more than\" in str(e) and \"artifacts\" in str(e):\n        result = provider.execute(inst, bundle_artifacts_version(code))\n    else:\n        raise","preventionTips":["Bundle many small outputs into a single json/zip artifact (respecting the extension allowlist).","Size `max_artifacts` in config to your real workload instead of relying on the default 20.","Remember collection is all-or-nothing: one extra file discards every artifact of that run."],"tags":["artifacts","ucloud","sandbox","resource-limits","count-limit"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}