{"record":{"id":"90856af9c2628342","repo":"abhigyanpatwari/GitNexus","slug":"dependency-symlink-is-dangling-or-escapes-its-snap","errorCode":null,"errorMessage":"dependency symlink is dangling or escapes its snapshot: {entry.path}","messagePattern":"dependency symlink is dangling or escapes its snapshot: (.+?)","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"critical","filePath":"eval/workflow_bench/task_assets.py","lineNumber":690,"sourceCode":"    for entry in entries:\n        if entry.kind != \"symlink\":\n            continue\n        target = PurePosixPath(entry.link_target)\n        relative_to_payload = entry.path.relative_to(manifest_boundary)\n        sandbox_resolved = PurePosixPath(\n            posixpath.normpath((sandbox_mount / relative_to_payload.parent / target).as_posix())\n        )\n        if sandbox_resolved != sandbox_boundary and sandbox_boundary not in sandbox_resolved.parents:\n            raise SandboxError(f\"dependency symlink escapes the sandbox workspace: {entry.path}\")\n        manifest_resolved = PurePosixPath(posixpath.normpath((entry.path.parent / target).as_posix()))\n        if manifest_resolved != manifest_boundary and manifest_boundary not in manifest_resolved.parents:\n            continue\n        link = container / Path(*entry.path.parts)\n        try:\n            resolved = link.resolve(strict=True)\n            resolved.relative_to(snapshot_boundary)\n        except (OSError, RuntimeError, ValueError) as exc:\n            raise SandboxError(f\"dependency symlink is dangling or escapes its snapshot: {entry.path}\") from exc\n\n\ndef _preflight_exact_root(clone: Path, relative: PurePosixPath) -> None:\n    \"\"\"Reject symlink/special hazards while permitting replaceable type conflicts.\"\"\"\n\n    flags = os.O_RDONLY | os.O_DIRECTORY | getattr(os, \"O_CLOEXEC\", 0) | getattr(os, \"O_NOFOLLOW\", 0)\n    current = os.open(clone, flags)\n    try:\n        for index, part in enumerate(relative.parts):\n            try:\n                mode = os.stat(part, dir_fd=current, follow_symlinks=False).st_mode\n            except FileNotFoundError:\n                return\n            last = index == len(relative.parts) - 1\n            if stat.S_ISLNK(mode):\n                role = \"target cannot be a symlink\" if last else \"target has a symlink parent\"\n                raise SandboxError(f\"sandbox_copy {role}: {relative}\")\n            if last:","sourceCodeStart":672,"sourceCodeEnd":708,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/task_assets.py#L672-L708","documentation":"Second-stage check in _validate_dependency_symlinks for symlinks that stay inside the sandbox but, when resolved against the on-disk snapshot (container/payload/...), either fail Path.resolve(strict=True) (dangling target) or land outside the snapshot's payload/ boundary.","triggerScenarios":"A symlink points at a file not captured in the same dependency snapshot (dangling); a symlink uses a ../../ chain that exits the payload dir into another dependency container or outside the snapshot.","commonSituations":"Partial capture where the link target was outside the captured subtree; dependency packaging that assumes a sibling directory not present in the snapshot.","solutions":["Include the symlink's target in the same dependency snapshot, or make the link relative to a captured path","Re-capture the dependency from a clean checkout so all link targets are present","Drop the symlink from the declaration if it is unused at runtime"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import posixpath\nfrom pathlib import Path, PurePosixPath\n\ndef dangling_or_escaping(container: Path, entries) -> list[str]:\n    boundary = (container / \"payload\").resolve(strict=True)\n    manifest_boundary = PurePosixPath(\"payload\")\n    bad = []\n    for e in entries:\n        if e.get(\"kind\") != \"symlink\":\n            continue\n        tgt = PurePosixPath(e[\"link_target\"])\n        manifest_resolved = PurePosixPath(posixpath.normpath((PurePosixPath(e[\"path\"]).parent / tgt).as_posix()))\n        if manifest_resolved != manifest_boundary and manifest_boundary not in manifest_resolved.parents:\n            continue  # checked elsewhere\n        link = container / Path(*PurePosixPath(e[\"path\"]).parts)\n        try:\n            link.resolve(strict=True).relative_to(boundary)\n        except (OSError, RuntimeError, ValueError):\n            bad.append(e[\"path\"])\n    return bad","typeGuard":null,"tryCatchPattern":"from eval.workflow_bench.proposer_sandbox import SandboxError\n\ntry:\n    snapshot = cache.prepare(task, repo=repo, resolved_sha=sha)\nexcept SandboxError as exc:\n    if \"dangling or escapes its snapshot\" in str(exc):\n        raise SystemExit(f\"dependency symlink target missing; re-capture the dependency: {exc}\") from exc\n    raise","preventionTips":["Capture the symlink target in the same dependency snapshot, or make links relative to captured paths","Re-capture dependencies from a clean checkout after any layout change","Drop runtime-unused symlinks from dependency declarations"],"tags":["sandbox","symlinks","dependencies","dangling-link"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}