abhigyanpatwari/GitNexus · error · SandboxError
transcript artifact metadata is malformed
Error message
transcript artifact metadata is malformed
What it means
After source is validated, the path must be a str and the sha256 must match the regex [0-9a-f]{64} (lowercase hex, exactly 64 chars). A non-string path, an uppercase-hex digest, a sha1 (40 chars), or a non-hex digest is treated as malformed metadata and rejected before any file is opened.
Source
Thrown at eval/workflow_bench/evolve.py:336
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)
if (
relative.is_absolute()
or len(relative.parts) != 2
or relative.parts[0] != "transcripts"
or any(part in {"", ".", ".."} for part in relative.parts)
):
raise SandboxError(f"unsafe results artifact path: {relative_value!r}")View on GitHub (pinned to d540b00184)
Solutions
- Normalize the digest to lowercase 64-char hex: `hashlib.sha256(data).hexdigest()` already yields this.
- Ensure path is a plain str (call str() if it is a Path), matching the 'transcripts/<name>' contract.
- Regenerate the row with the current runner so digest and path are written canonically.
Example fix
# before
{"path": "transcripts/r.json", "sha256": "ABCDEF0123...", "bytes": 12, "source": "parent-captured-stream-json"}
# after
import hashlib
digest = hashlib.sha256(blob).hexdigest() # lowercase, 64 hex
row = {"path": "transcripts/r.json", "sha256": digest, "bytes": 12, "source": PARENT_EVENT_STREAM_SOURCE} Defensive patterns
Strategy: validation
Validate before calling
import re
from pathlib import PurePosixPath
HEX64 = re.compile(r"[0-9a-f]{64}")
def transcript_path_and_digest_ok(metadata: dict) -> bool:
rel = metadata.get("path")
digest = metadata.get("sha256")
return isinstance(rel, str) and bool(HEX64.fullmatch(str(digest))) Type guard
import re
HEX64 = re.compile(r"[0-9a-f]{64}")
def is_valid_sha256_hex(value: object) -> bool:
return isinstance(value, str) and bool(HEX64.fullmatch(value)) Prevention
- Always produce digests with hashlib.sha256(...).hexdigest() (lowercase, 64 hex).
- Store paths as plain 'transcripts/<name>' strings.
- Validate digest format at write time, not just read time.
When it happens
Trigger: path is None/a list/a Path object; sha256 is uppercase ('ABCDEF...'), a sha1 (40 chars), a sha256 with dashes, or contains non-hex characters; a base64 digest was recorded by mistake.
Common situations: A runner that uppercased the digest; sha1 from a legacy path; a path stored as a structured value; truncation/copy errors shortening the digest.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- transcript artifact metadata must contain only path, sha256,
- transcript artifact byte count must be an integer
- transcript artifact source is not the parent event stream
- transcript artifact exceeds the bounded run-output limit
- {label} is unavailable: {path}: {exc}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/95661da48a3c1f69.
Report an issue: GitHub.