{"record":{"id":"3b8bb872e95085f6","repo":"infiniflow/ragflow","slug":"artifact-directory-nesting-exceeds-max-artifact-d","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/tenki.py","lineNumber":446,"sourceCode":"            raise RuntimeError(f\"Unsupported language for Tenki provider: {language}\")\n\n        script_path = posixpath.join(remote_work_dir, script_name)\n        sandbox.fs.write_text(script_path, script_content)\n        return script_path, [executable, script_path]\n\n    def _validate_output_size(self, stdout: str, stderr: str) -> None:\n        output_size = len((stdout or \"\").encode(\"utf-8\")) + len((stderr or \"\").encode(\"utf-8\"))\n        if output_size > self.max_output_bytes:\n            raise RuntimeError(f\"Tenki execution output exceeded {self.max_output_bytes} bytes.\")\n\n    def _collect_artifacts(self, sandbox, artifacts_dir: str) -> list[dict[str, Any]]:\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        if depth > MAX_ARTIFACT_DEPTH:\n            raise RuntimeError(f\"Artifact directory nesting exceeds {MAX_ARTIFACT_DEPTH} levels: {relative_dir}\")\n\n        errors = self._tenki_errors()\n        try:\n            entries = sandbox.fs.list(current_dir)\n        except errors.FileNotFoundError:\n            return\n        except FileNotFoundError:\n            return\n\n        # fs.list returns each entry's basename in `.path`, not an absolute\n        # path, so join it onto the directory being listed.\n        for entry in sorted(entries, key=lambda item: item.path):\n            name = posixpath.basename(entry.path)\n            remote_path = posixpath.join(current_dir, name)\n            relative_path = posixpath.join(relative_dir, name) if relative_dir else name\n\n            # Reject symlinks. `is_symlink` is not populated by every SDK\n            # release, so also inspect the stat mode bits as the reliable check.","sourceCodeStart":428,"sourceCodeEnd":464,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/agent/sandbox/providers/tenki.py#L428-L464","documentation":"Raised during artifact collection when the recursive directory walk under artifacts/ exceeds MAX_ARTIFACT_DEPTH (16 levels). The guard exists to bound traversal of untrusted, potentially pathological directory trees (including symlink-loop constructs) produced by executed code.","triggerScenarios":"User script creates nested directories deeper than 16 levels inside the artifacts dir (e.g. a loop doing os.makedirs('a/'*100)), or a directory structure with cycles that the symlink rejection did not prune before depth accrues.","commonSituations":"LLM-generated code copying deep node_modules-style trees into artifacts, archive extraction with deeply nested paths, or adversarial code trying to exhaust the walker.","solutions":["Fix the script to flatten or limit artifact directory depth (keep outputs at the top level of artifacts/).","Write only final result files into artifacts/, not source trees or dependency directories.","If legitimate output genuinely needs more nesting, raise MAX_ARTIFACT_DEPTH — but treat depth blowups as a code smell first."],"exampleFix":"# before\n# script: for i in range(100): os.makedirs(f'artifacts/{\"d/\"*i}x')\n\n# after\n# script: os.makedirs('artifacts', exist_ok=True); shutil.copy(result, 'artifacts/result.csv')","handlingStrategy":"validation","validationCode":"# in generated code, keep artifacts flat\n# depth check helper the script can run:\n# for root, dirs, files in os.walk('artifacts'):\n#     assert root.count(os.sep) - 'artifacts'.count(os.sep) <= 16","typeGuard":null,"tryCatchPattern":"try:\n    result = provider.execute_code(instance_id, code)\nexcept RuntimeError as exc:\n    if \"nesting exceeds\" in str(exc):\n        result = provider.execute_code(instance_id, flattened_artifacts_version(code))\n    else:\n        raise","preventionTips":["Generate scripts that write outputs directly under artifacts/, never deep trees or extracted archives.","Treat depth blowups as suspicious output from untrusted code."],"tags":["artifacts","limits","security","tenki"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}