abhigyanpatwari/GitNexus · error · SandboxError

sandbox_dependencies must be a list

Error message

sandbox_dependencies must be a list

What it means

Type guard in validate_no_prebuilt_graph_assets, symmetric to error 553. The task spec's 'sandbox_dependencies' field must be a list; non-list values are rejected before any per-item source/target scan. Omitting the field defaults to an empty list and is allowed.

Source

Thrown at eval/workflow_bench/sanitized_graph.py:96

        return False
    return (
        relative.parts[0] == ".gitnexus" or relative == HIDDEN_HARNESS_PATH or HIDDEN_HARNESS_PATH in relative.parents
    )


def validate_no_prebuilt_graph_assets(task: Mapping[str, Any]) -> None:
    """Reject declarations that could reintroduce an unsanitized graph/oracle."""

    sandbox_copy = task.get("sandbox_copy", [])
    if not isinstance(sandbox_copy, list):
        raise SandboxError("sandbox_copy must be a list")
    for value in sandbox_copy:
        if isinstance(value, str) and _is_restricted_path(value):
            raise SandboxError(f"sandbox_copy cannot import prebuilt graph or harness data: {value}")

    dependencies = task.get("sandbox_dependencies", [])
    if not isinstance(dependencies, list):
        raise SandboxError("sandbox_dependencies must be a list")
    for item in dependencies:
        if not isinstance(item, Mapping):
            continue
        for field in ("source", "target"):
            value = item.get(field)
            if isinstance(value, str) and _is_restricted_path(value):
                raise SandboxError(f"sandbox dependency cannot expose prebuilt graph or harness data: {value}")


def _replace_control_file(root: Path, name: str, payload: bytes) -> None:
    path = root / name
    try:
        metadata = path.lstat()
    except FileNotFoundError:
        metadata = None
    if metadata is not None:
        if stat.S_ISDIR(metadata.st_mode):
            raise SandboxError(f"target-controlled {name} must not be a directory")

View on GitHub (pinned to d540b00184)

Solutions

  1. Wrap the dependency in a list: 'sandbox_dependencies: [{source: a, target: b}]' or use a YAML block sequence.
  2. Validate locally: assert isinstance(spec.get('sandbox_dependencies', []), list) before submitting the task.
  3. Check each entry is a Mapping with source/target if you want to fail fast before the harness does.
  4. Consult the task schema for the canonical dependency entry shape.

Example fix

# before
sandbox_dependencies: {source: vendor/lib, target: lib}
# after
sandbox_dependencies:
  - source: vendor/lib
    target: lib
Defensive patterns

Strategy: type-guard

Validate before calling

import yaml
from pathlib import Path

task = yaml.safe_load(Path("task.yaml").read_text())
if "sandbox_dependencies" in task and not isinstance(task["sandbox_dependencies"], list):
    raise SystemExit(
        f"sandbox_dependencies must be a list, got {type(task['sandbox_dependencies']).__name__}"
    )

Type guard

from collections.abc import Mapping

def sandbox_dependencies_well_formed(task: Mapping) -> bool:
    sd = task.get("sandbox_dependencies", [])
    return isinstance(sd, list) and all(isinstance(i, Mapping) for i in sd)

Try / catch

try:
    validate_no_prebuilt_graph_assets(task)
except SandboxError as exc:
    if "sandbox_dependencies must be a list" in str(exc):
        log.error("task.sandbox_dependencies must be a YAML/JSON list of mappings")
    raise

Prevention

When it happens

Trigger: sandbox_dependencies is declared as a single mapping or a scalar rather than a sequence of dependency mappings. Each entry is later expected to be a Mapping with 'source' and 'target' fields.

Common situations: Author wrote a single dependency as a bare mapping instead of a one-element list; YAML indentation collapsed a list into a mapping; schema drift after a task-format revision.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12). Data as JSON: /api/errors/351aaa1cb34f8f95. Report an issue: GitHub.