{"record":{"id":"739892a2ba827f96","repo":"abhigyanpatwari/GitNexus","slug":"dependency-symlink-is-unreadable-or-not-utf-8-re","errorCode":null,"errorMessage":"dependency symlink is unreadable or not UTF-8: {relative}","messagePattern":"dependency symlink is unreadable or not UTF-8: (.+?)","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/task_assets.py","lineNumber":472,"sourceCode":"                kind=\"file\",\n                size=copied,\n                sha256=digest.hexdigest(),\n                mode=captured_mode,\n            )\n        )\n\n    def _copy_symlink(\n        self,\n        parent_descriptor: int,\n        name: str,\n        relative: PurePosixPath,\n        before: os.stat_result,\n    ) -> None:\n        try:\n            target = os.readlink(name, dir_fd=parent_descriptor)\n            target_bytes = target.encode(\"utf-8\")\n        except (OSError, UnicodeEncodeError) as exc:\n            raise SandboxError(f\"dependency symlink is unreadable or not UTF-8: {relative}\") from exc\n        if not target or PurePosixPath(target).is_absolute() or \"\\x00\" in target:\n            raise SandboxError(f\"dependency symlink must be a bounded relative link: {relative}\")\n        if len(target_bytes) > MAX_TASK_ASSET_PATH_BYTES:\n            raise SandboxError(f\"dependency symlink target exceeds the path limit: {relative}\")\n        if self.budget.total_bytes + len(target_bytes) > MAX_TASK_ASSET_BYTES:\n            raise SandboxError(\"sandbox_copy exceeds the total byte limit\")\n        destination = self.destination / Path(*relative.parts)\n        os.symlink(target, destination)\n        after = os.stat(name, dir_fd=parent_descriptor, follow_symlinks=False)\n        if (\n            _mutation_identity(before) != _mutation_identity(after)\n            or os.readlink(\n                name,\n                dir_fd=parent_descriptor,\n            )\n            != target\n        ):\n            raise SandboxError(f\"dependency symlink changed while snapshotting: {relative}\")","sourceCodeStart":454,"sourceCodeEnd":490,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/task_assets.py#L454-L490","documentation":"Raised by _SnapshotBuilder._copy_symlink when os.readlink fails (OSError — e.g. permission denied, dangling link on some kernels, ENOENT) or when the link target string cannot be encoded as UTF-8 (UnicodeEncodeError). Symlinks are only followed for sandbox_dependencies (allow_symlinks=True), never for sandbox_copy roots. The snapshot must store the target verbatim, so non-UTF-8 or unreadable links cannot be captured faithfully.","triggerScenarios":"A sandbox_dependency source tree contains a symlink whose target is a path with bytes invalid in the current locale, or a symlink the reader lacks permission to readlink, or a symlink that was deleted between listing the parent directory and calling readlink (TOCTOU removal).","commonSituations":"node_modules contains a symlink to a path with non-UTF-8 bytes (rare on Linux but possible with certain package managers or mounted volumes). A broken/deleted symlink inside a dependency tree. Permission modes that deny readlink to the harness user.","solutions":["Run `find <dependency-source> -type l -print0 | xargs -0 readlink` and identify any link that errors or prints garbage bytes.","Remove or recreate offending symlinks so they point to valid UTF-8 relative targets.","Ensure the harness user has read permission on the parent directory and the symlink entry (chmod +r on the dir if needed).","If the link was deleted mid-capture, re-run after quiescing the tree."],"exampleFix":"# before — a node_modules symlink with a non-UTF-8 target\nls -la node_modules/.bin\n\n# fix: recreate the link with a clean relative target\nrm node_modules/.bin/bad-link\nln -s ../some-package/cli.js node_modules/.bin/bad-link","handlingStrategy":"validation","validationCode":"from pathlib import Path\nimport os, stat\n\ndef validate_dependency_symlinks_readable(dep_source: Path) -> None:\n    for current, dirs, files in os.walk(dep_source, followlinks=False):\n        entries = dirs + files\n        for name in entries:\n            p = Path(current) / name\n            if p.is_symlink():\n                try:\n                    target = os.readlink(p)\n                    target.encode(\"utf-8\")\n                except (OSError, UnicodeEncodeError) as exc:\n                    raise ValueError(f\"unreadable/non-UTF-8 symlink: {p}: {exc}\") from exc\n\nfor d in task.get(\"sandbox_dependencies\", []):\n    validate_dependency_symlinks_readable(repo_path / d[\"source\"])","typeGuard":"import os\nfrom pathlib import Path\n\ndef symlink_is_utf8_readable(p: Path) -> bool:\n    try:\n        os.readlink(p).encode(\"utf-8\")\n        return True\n    except (OSError, UnicodeEncodeError):\n        return False","tryCatchPattern":"from eval.workflow_bench.propposer_sandbox import SandboxError\n\ntry:\n    snapshot = cache.prepare(task, repo=repo, resolved_sha=sha)\nexcept SandboxError as exc:\n    if \"unreadable or not UTF-8\" in str(exc):\n        # locate and recreate the offending link, then re-run\n        raise\n    raise","preventionTips":["Reinstall node_modules with a standard package manager so all links are clean UTF-8.","Audit dependency symlinks with `find <source> -type l -print0 | xargs -0 -I{} readlink {}` before capture.","Ensure the harness user has read permission on the source tree."],"tags":["sandbox","symlink","dependencies","encoding","permissions"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}