{"record":{"id":"6ebd359503769e43","repo":"infiniflow/ragflow","slug":"artifact-directory-nesting-exceeds-max-artifact-d-6ebd35","errorCode":null,"errorMessage":"Artifact directory nesting exceeds {MAX_ARTIFACT_DEPTH} levels: {relative_dir}","messagePattern":"Artifact directory nesting exceeds (.+?) levels: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"agent/sandbox/providers/ucloud_agent_sandbox.py","lineNumber":416,"sourceCode":"        sandbox.files.write(script_path, script_content, request_timeout=self.timeout)\n        return script_path, executable\n\n    def _validate_output_size(self, stdout: str, stderr: str) -> None:\n        \"\"\"Reject combined standard output that exceeds the configured limit.\"\"\"\n        output_size = len(stdout.encode(\"utf-8\")) + len(stderr.encode(\"utf-8\"))\n        if output_size > self.max_output_bytes:\n            raise RuntimeError(f\"UCloud Agent Sandbox execution output exceeded {self.max_output_bytes} bytes.\")\n\n    def _collect_artifacts(self, sandbox, artifacts_dir: str) -> list[dict[str, Any]]:\n        \"\"\"Collect allowed files from the execution artifact directory.\"\"\"\n        artifacts: list[dict[str, Any]] = []\n        self._collect_artifacts_recursive(sandbox, artifacts_dir, \"\", artifacts, depth=0)\n        return artifacts\n\n    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()","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/sandbox/providers/ucloud_agent_sandbox.py#L398-L434","documentation":"Raised while recursively collecting artifacts when directory depth exceeds MAX_ARTIFACT_DEPTH. The collector starts at depth 0 under the artifacts directory and recurses per directory level; the cap prevents runaway traversal of deep trees and guards the provider against path explosion.","triggerScenarios":"Executed code creating nested directories under the artifacts dir deeper than MAX_ARTIFACT_DEPTH (e.g. recursive mkdir loops, unpacked archives with deep paths, or accidental recursive copies).","commonSituations":"Code that unpacks a tarball with many nested levels; a script copying a directory into itself; build tools (node_modules-style nesting) writing into the artifacts folder.","solutions":["Flatten artifact output — write files at shallow depths under the artifacts directory.","Exclude deep trees (node_modules, .git, extracted archives) from the artifacts dir.","If depth is legitimate, raise MAX_ARTIFACT_DEPTH in a patch or restructure output.","Catch RuntimeError after execute and inform the user code that its artifact layout is too deep."],"exampleFix":"# before\nimport shutil, os\nos.makedirs(\"artifacts/a/b/c/.../z\", exist_ok=True)  # 30+ levels -> RuntimeError\n\n# after\nos.makedirs(\"artifacts/out\", exist_ok=True)\nshutil.copy(\"deep/tree/file.txt\", \"artifacts/out/file.txt\")","handlingStrategy":"try-catch","validationCode":"# bound depth in the user code you dispatch\nif \"artifacts\" in code and \"os.makedirs\" in code:\n    # naive guard: reject unbounded recursive mkdir patterns before executing\n    assert \"while\" not in code.split(\"makedirs\")[-1][:60], \"possible unbounded mkdir\"","typeGuard":"def is_artifact_depth_error(exc: RuntimeError) -> bool:\n    return \"nesting exceeds\" in str(exc)","tryCatchPattern":"try:\n    result = provider.execute(inst, code)\nexcept RuntimeError as e:\n    if \"nesting exceeds\" in str(e):\n        result = retry_with_flattened_artifacts(inst, code)  # e.g. add a pre-execution rewrite\n    else:\n        raise","preventionTips":["Write artifacts as flat or shallowly nested trees; copy needed files up rather than preserving deep structure.","Never unpack archives or vendor dependency trees (node_modules) into the artifacts directory.","Watch for scripts that copy a directory into itself — the classic infinite-recursion producer."],"tags":["artifacts","ucloud","sandbox","resource-limits","filesystem"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}