{"record":{"id":"4b5fa43a4c8565de","repo":"abhigyanpatwari/GitNexus","slug":"sandbox-copy-must-be-a-list-of-nonblank-repository","errorCode":null,"errorMessage":"sandbox_copy must be a list of nonblank repository-relative paths","messagePattern":"sandbox_copy must be a list of nonblank repository-relative paths","errorType":"exception","errorClass":"SandboxError","httpStatus":null,"severity":"error","filePath":"eval/workflow_bench/task_assets.py","lineNumber":545,"sourceCode":"    def ensure_directory(self, relative: PurePosixPath) -> None:\n        \"\"\"Record and create one extra directory inside this snapshot.\n\n        Used for harness-owned mount points that must exist in the captured\n        bytes rather than be created against a read-only bind at runtime.\n        \"\"\"\n\n        self._record_directory(relative)\n\n    def finished_entries(self) -> tuple[AssetManifestEntry, ...]:\n        return tuple(sorted(self.entries.values(), key=lambda entry: entry.path.as_posix()))\n\n\ndef _sandbox_copy_declarations(\n    task: Mapping[str, Any],\n) -> tuple[tuple[str, ...], tuple[PurePosixPath, ...]]:\n    raw_declarations = task.get(\"sandbox_copy\", [])\n    if not isinstance(raw_declarations, list) or not all(isinstance(item, str) and item for item in raw_declarations):\n        raise SandboxError(\"sandbox_copy must be a list of nonblank repository-relative paths\")\n    declarations = tuple(raw_declarations)\n    paths: list[PurePosixPath] = []\n    for raw in declarations:\n        relative = PurePosixPath(raw)\n        if relative.is_absolute() or not relative.parts or \"..\" in relative.parts:\n            raise SandboxError(f\"sandbox_copy must be a repository-relative path: {raw!r}\")\n        _validate_manifest_path(relative)\n        paths.append(relative)\n    for index, path in enumerate(paths):\n        for other in paths[index + 1 :]:\n            if path == other or path in other.parents or other in path.parents:\n                raise SandboxError(f\"sandbox_copy declarations overlap: {path} and {other}\")\n    return declarations, tuple(paths)\n\n\ndef _sandbox_dependency_declarations(\n    task: Mapping[str, Any],\n) -> tuple[_DependencyDeclaration, ...]:","sourceCodeStart":527,"sourceCodeEnd":563,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/d540b00184d71a896261ee02670da9a92d59d8f7/eval/workflow_bench/task_assets.py#L527-L563","documentation":"Raised by _sandbox_copy_declarations when the task's `sandbox_copy` field is absent-as-non-list or is a list containing any element that is not a non-blank string. The field must be a list of repository-relative path strings, each truthy (non-empty after strip semantics of truthiness). This is the top-level schema gate for sandbox_copy declarations, evaluated before any path validation.","triggerScenarios":"Task JSON has `\"sandbox_copy\": \"src\"` (a string, not a list), `\"sandbox_copy\": [\"src\", 123]` (mixed types), `\"sandbox_copy\": [\"src\", \"\"]` (blank element), `\"sandbox_copy\": [\"src\", null]`, or `\"sandbox_copy\": {\"paths\": [...]}` (a dict). The check is `isinstance(item, str) and item` for every element.","commonSituations":"Hand-writing task YAML/JSON and forgetting the list brackets. Copying a single-path shorthand from another tool that accepts a bare string. A serialization bug that emits None or empty strings for missing optional paths. Schema drift between task authoring and the harness contract.","solutions":["Ensure `sandbox_copy` is a JSON list of non-empty strings: `[\"path/one\", \"path/two\"]`.","Validate the task document against the expected schema before passing it to prepare() (see validationCode).","Omit the field entirely (`sandbox_copy: []` or absent) if no paths are needed — both are accepted.","Strip whitespace and drop blanks at authoring time so no empty-string element reaches the harness."],"exampleFix":"// before\n{\"sandbox_copy\": \"repo/src\"}\n// or\n{\"sandbox_copy\": [\"repo/src\", \"\", null]}\n\n// after\n{\"sandbox_copy\": [\"repo/src\"]}","handlingStrategy":"type-guard","validationCode":"def validate_sandbox_copy_shape(task: dict) -> None:\n    raw = task.get(\"sandbox_copy\", [])\n    if not isinstance(raw, list):\n        raise ValueError(\"sandbox_copy must be a list\")\n    for item in raw:\n        if not isinstance(item, str) or not item:\n            raise ValueError(f\"sandbox_copy entries must be nonblank strings, got {item!r}\")\n\nvalidate_sandbox_copy_shape(task)","typeGuard":"from typing import Any\n\ndef is_sandbox_copy_list(value: Any) -> bool:\n    return (\n        isinstance(value, list)\n        and all(isinstance(item, str) and item for item in value)\n    )","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 \"must be a list of nonblank\" in str(exc):\n        # fix the sandbox_copy field shape in the task document\n        raise\n    raise","preventionTips":["Always author sandbox_copy as a JSON array of non-empty strings, even for one path.","Validate the task document against a schema (e.g. pydantic or jsonschema) before prepare.","Omit the field or use [] when no paths are needed."],"tags":["sandbox","config","validation","task-declaration","schema"],"backgroundTag":null,"analyzedSha":"d540b00184d71a896261ee02670da9a92d59d8f7","analyzedAt":"2026-08-12T19:50:25.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}