abhigyanpatwari/GitNexus · error · ValueError
event-stream artifact path must be transcripts/<file>: {rela
Error message
event-stream artifact path must be transcripts/<file>: {relative_path!r} What it means
Thrown by persist_parent_event_stream (runner_sessions.py) when validating where an event-stream artifact may be written. The relative path must be exactly two POSIX parts — 'transcripts' as the first component and a single filename as the second — and must not be absolute. This narrow shape blocks arbitrary writes anywhere under the output root and is the first of two path checks.
Source
Thrown at eval/workflow_bench/runner_sessions.py:152
tools.extend(GITNEXUS_MUTATING_TOOLS)
return tools
def _persist_parent_event_stream(
raw: bytes,
*,
output_dir: Path,
relative_path: str,
secrets: tuple[str, ...],
) -> dict[str, Any]:
"""Persist only the complete event stream captured by the trusted parent."""
# Parsing before persistence proves the artifact is complete structured
# evidence, rather than arbitrary output injected through a tool result.
events = _parse_parent_event_stream(raw)
relative = PurePosixPath(relative_path)
if relative.is_absolute() or len(relative.parts) != 2 or relative.parts[0] != "transcripts":
raise ValueError(f"event-stream artifact path must be transcripts/<file>: {relative_path!r}")
if any(part in {"", ".", ".."} for part in relative.parts):
raise ValueError(f"unsafe event-stream artifact path: {relative_path!r}")
root = output_dir.expanduser().absolute()
root_mode = root.lstat().st_mode
if stat.S_ISLNK(root_mode) or not stat.S_ISDIR(root_mode) or root.resolve(strict=True) != root:
raise ValueError(f"event-stream output root must be a real non-symlink directory: {root}")
transcript_dir = root / relative.parts[0]
try:
transcript_dir.mkdir(mode=0o700)
except FileExistsError:
mode = transcript_dir.lstat().st_mode
if stat.S_ISLNK(mode) or not stat.S_ISDIR(mode):
raise ValueError(f"event-stream artifact parent must be a real directory: {transcript_dir}")
transcript_dir.chmod(0o700)
def redact_value(value: Any) -> Any:
if isinstance(value, str):View on GitHub (pinned to d540b00184)
Solutions
- Always pass a relative_path of the form 'transcripts/<single-filename>'.
- If you need subdirectories, flatten to a single filename under transcripts/ (the harness layout does not nest further).
- Strip any leading '/' and any 'transcripts/' prefix you may have doubled.
- Centralize path construction in one helper that always emits the two-part form.
Example fix
// before persist_parent_event_stream(raw, output_dir=out, relative_path='session_x/transcript.json', secrets=secrets) // after persist_parent_event_stream(raw, output_dir=out, relative_path='transcripts/session_x.json', secrets=secrets)
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import PurePosixPath
def is_valid_transcript_path(relative_path: str) -> bool:
p = PurePosixPath(relative_path)
return (not p.is_absolute() and len(p.parts) == 2 and p.parts[0] == 'transcripts') Type guard
from pathlib import PurePosixPath
def is_valid_transcript_path(relative_path: str) -> bool:
p = PurePosixPath(relative_path)
return (not p.is_absolute() and len(p.parts) == 2 and p.parts[0] == 'transcripts') Try / catch
try:
persist_parent_event_stream(raw, output_dir=out, relative_path=rp, secrets=secrets)
except ValueError as e:
if 'must be transcripts/<file>' in str(e):
# rebuild relative_path as 'transcripts/<filename>' and retry
raise
raise Prevention
- Always build relative_path as f'transcripts/{filename}'.
- Never nest subdirectories under transcripts/.
- Centralize path construction in one helper that emits the two-part form.
- Strip leading '/' and any duplicated 'transcripts/' prefix.
When it happens
Trigger: relative.is_absolute() is True, or len(relative.parts) != 2, or relative.parts[0] != 'transcripts'. E.g. the caller passed 'foo/bar.json', 'transcripts/a/b.json', an absolute '/x/y', or just 'file.json'.
Common situations: A session writer passed a nested path (transcripts/sub/file); a path from another component that does not prefix with 'transcripts'; an absolute path leaked in from a config; a caller that builds the path with the wrong base.
Related errors
- unsafe event-stream artifact path: {relative_path!r}
- {label} contains an unsafe path component: {relative}
- unsafe results artifact path: {relative_value!r}
- Invalid group name "${name}". Names must start with a letter
- {label} must be a real non-symlink directory: {path}
AI-assisted analysis of abhigyanpatwari/GitNexus@d540b00184 (2026-08-12).
Data as JSON: /api/errors/f9a2fec1c2e53c11.
Report an issue: GitHub.