abhigyanpatwari/GitNexus · error · SandboxError
transcript artifact metadata must contain only path, sha256,
Error message
transcript artifact metadata must contain only path, sha256, bytes, and source
What it means
_transcript_artifact_metadata pins the admissible schema to exactly four keys: {path, sha256, bytes, source}. Extra keys (e.g. 'mtime', 'mtime_ns') or missing ones mean the row was not produced by the trusted runner, so the harness rejects it rather than guess which fields to trust.
Source
Thrown at eval/workflow_bench/evolve.py:329
current = root
for part in relative.parts[:-1]:
current /= part
try:
metadata = current.lstat()
except OSError as exc:
raise SandboxError(f"results artifact parent is unavailable: {current}: {exc}") from exc
if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISDIR(metadata.st_mode):
raise SandboxError(f"results artifact parent must be a real directory: {current}")
if transcript and stat.S_IMODE(metadata.st_mode) & 0o077:
raise SandboxError(f"transcript artifact parent must be owner-only: {current}")
return root / Path(*relative.parts)
def _transcript_artifact_metadata(metadata: Any) -> tuple[str, str, int]:
"""Validate transcript metadata without touching any host path."""
if not isinstance(metadata, dict) or set(metadata) != {"path", "sha256", "bytes", "source"}:
raise SandboxError("transcript artifact metadata must contain only path, sha256, bytes, and source")
relative = metadata["path"]
expected_digest = metadata["sha256"]
expected_size = metadata["bytes"]
if metadata["source"] != runner_sessions.PARENT_EVENT_STREAM_SOURCE:
raise SandboxError("transcript artifact source is not the parent event stream")
if not isinstance(relative, str) or not re.fullmatch(r"[0-9a-f]{64}", str(expected_digest)):
raise SandboxError("transcript artifact metadata is malformed")
if not isinstance(expected_size, int) or isinstance(expected_size, bool):
raise SandboxError("transcript artifact byte count must be an integer")
if expected_size < 0 or expected_size > runner.MAX_TRANSCRIPT_BYTES:
raise SandboxError("transcript artifact exceeds the bounded run-output limit")
return relative, expected_digest, expected_size
def _normalized_transcript_artifact_path(relative_value: str) -> str:
"""Apply the transcript path contract without touching the filesystem."""
relative = PurePosixPath(relative_value)View on GitHub (pinned to d540b00184)
Solutions
- Diff the row against the trusted runner's writer (runner_sessions) and align key names exactly.
- Regenerate the results row with the current runner so the schema matches.
- If adding a field is intended, extend the allowed set in _transcript_artifact_metadata deliberately, with review.
Example fix
# before
{"path": "transcripts/r.json", "sha256": "<64hex>", "bytes": 12, "source": "parent-captured-stream-json", "mtime": 123}
# after (drop the extra key)
{"path": "transcripts/r.json", "sha256": "<64hex>", "bytes": 12, "source": "parent-captured-stream-json"} Defensive patterns
Strategy: type-guard
Validate before calling
from eval.workflow_bench.evolve import _transcript_artifact_metadata # reuse the exact check
TRANSCRIPT_KEYS = {"path", "sha256", "bytes", "source"}
def transcript_metadata_shape_ok(metadata: dict) -> bool:
return isinstance(metadata, dict) and set(metadata) == TRANSCRIPT_KEYS Type guard
TRANSCRIPT_KEYS = {"path", "sha256", "bytes", "source"}
def is_transcript_metadata(value: object) -> TypeGuard[dict]:
return isinstance(value, dict) and set(value) == TRANSCRIPT_KEYS Prevention
- Write transcript rows only via runner_sessions so the schema cannot drift.
- Pin the schema in a shared constant both writer and validator import.
- Reject hand-edited results.jsonl in CI.
When it happens
Trigger: A results.jsonl transcript_artifacts row carries an extra field, omits one of the four, or uses a renamed key (e.g. 'size' instead of 'bytes'); a hand-edited or third-party runner wrote the row.
Common situations: Runner version skew after a schema change; manual edits to results.jsonl; a forked runner that adds metadata.
Related errors
- transcript artifact metadata is malformed
- transcript artifact byte count must be an integer
- unsafe results artifact path: {relative_value!r}
- transcript artifact source is not the parent event stream
- transcript artifact exceeds the bounded run-output limit
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/529adb60b5f20c2a.
Report an issue: GitHub.