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

  1. Always pass a relative_path of the form 'transcripts/<single-filename>'.
  2. If you need subdirectories, flatten to a single filename under transcripts/ (the harness layout does not nest further).
  3. Strip any leading '/' and any 'transcripts/' prefix you may have doubled.
  4. 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

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


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