abhigyanpatwari/GitNexus · error · SandboxError
evidence destination already exists: {destination}
Error message
evidence destination already exists: {destination} What it means
Raised by stage_evidence_bundle when the destination directory already exists (destination.resolve().exists() is true). The writer wants to mkdir(parents=True, mode=0o700) into a fresh path and treats a pre-existing destination as a collision it must not silently overwrite, since clobbering could mix old unredacted bytes with new evidence.
Source
Thrown at eval/workflow_bench/proposer_sandbox.py:222
raw = value
elif isinstance(value, str):
raw = value.encode()
else:
raw = (json.dumps(value, sort_keys=True, separators=(",", ":")) + "\n").encode()
return redact_text(raw.decode(errors="replace"), secrets).encode()
def stage_evidence_bundle(
destination: Path,
entries: Mapping[str, Any],
*,
secrets: Sequence[str] = (),
) -> Path:
"""Write a redacted owner-only evidence bundle with hard byte caps."""
destination = destination.resolve()
if destination.exists():
raise SandboxError(f"evidence destination already exists: {destination}")
destination.mkdir(parents=True, mode=0o700)
destination.chmod(0o700)
total = 0
try:
for name, value in entries.items():
relative = PurePosixPath(name)
if len(relative.parts) != 1 or relative.name in {"", ".", ".."}:
raise SandboxError(f"evidence names must be simple relative files: {name!r}")
payload = _evidence_bytes(value, secrets)
if len(payload) > MAX_EVIDENCE_FILE_BYTES:
raise SandboxError(f"evidence exceeds the per-file limit: {name}")
total += len(payload)
if total > MAX_BUNDLE_BYTES:
raise SandboxError("evidence bundle exceeds the total byte limit")
path = destination / relative.name
path.write_bytes(payload)
path.chmod(0o600)
except BaseException:View on GitHub (pinned to d540b00184)
Solutions
- Pass a fresh per-run destination: append a unique suffix (uuid, timestamp, pid) or use tempfile.mkdtemp as the parent and a new leaf name.
- Delete the existing destination before staging if you are sure it is stale: shutil.rmtree(destination, ignore_errors=True) then retry.
- On retry, generate a new destination under the session private_root rather than reusing the literal same path.
- Ensure the orchestrator cleans the staging root at session end so retries start clean.
Example fix
// before
dest = Path("/tmp/wfbench/task-7/evidence") # exists from prior crash
stage_evidence_bundle(dest, entries)
// after
dest = Path(tempfile.mkdtemp(prefix="evidence-")) / "evidence"
stage_evidence_bundle(dest, entries) Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
import tempfile, uuid
def fresh_destination(base: Path) -> Path:
return base / f'evidence-{uuid.uuid4().hex}' if base.exists() else base
dest = fresh_destination(Path(tempfile.mkdtemp(prefix='wfbench-'))) / 'bundle' Type guard
null
Try / catch
try:
stage_evidence_bundle(dest, entries, secrets=secrets)
except SandboxError as exc:
if 'already exists' in str(exc):
import shutil
shutil.rmtree(dest, ignore_errors=True)
stage_evidence_bundle(dest, entries, secrets=secrets)
raise Prevention
- Use a unique destination per run (uuid/timestamp/pid suffix).
- Clean the staging root at the start of each run.
- Never reuse a destination across retries.
- Use tempfile.mkdtemp so the parent is always fresh.
When it happens
Trigger: Calling stage_evidence_bundle with a destination Path that already exists on disk (file or directory), including a leftover bundle from a previous run or retry.
Common situations: A retry reuses the same destination path after a prior run crashed mid-stage; the destination sits under a temp base whose name is deterministic per task and the prior artifact was not cleaned; two concurrent tasks share a staging root without per-run names; a SIGKILL beat the failure-path rmtree.
Related errors
- evidence source must be a regular non-symlink file: {path}
- results directory is unavailable: {root}: {exc}
- transcript artifact is unavailable: {path}: {exc}
- evidence path is unreadable: {value}: {exc}
- evidence must be a regular non-symlink file: {value}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/2f17a7932b2e82f8.
Report an issue: GitHub.