can1357/oh-my-pi · error · RuntimeError

No session - output artifacts unavailable

Error message

No session - output artifacts unavailable

What it means

The prelude's output() writes result artifacts to an artifacts directory taken from PI_ARTIFACTS_DIR, falling back to deriving it from PI_SESSION_FILE (session file minus .jsonl extension). When neither env var is set there is no session context, so it emits an error status and raises RuntimeError 'No session - output artifacts unavailable'. The prelude is designed to run inside an eval session and refuses to guess where artifacts should go.

Source

Thrown at packages/coding-agent/src/eval/py/prelude.py:181

            Single ID: str (format='raw'/'stripped') or dict (format='json')
            Multiple IDs: list of dict with 'id' and 'content'/'data' keys

        Examples:
            output('scout_0')  # Read as raw text
            output('reviewer_0', format='json')  # Read with metadata
            output('scout_0', query='.files[0]')  # Extract JSON field
            output('scout_0', offset=10, limit=20)  # Lines 10-29
            output('scout_0', 'reviewer_1')  # Read multiple outputs
        """
        # Prefer PI_ARTIFACTS_DIR so subagents resolve through the parent's
        # shared artifacts dir; fall back to deriving from PI_SESSION_FILE
        # for legacy callers / top-level sessions where the two coincide.
        artifacts_dir = os.environ.get("PI_ARTIFACTS_DIR")
        if not artifacts_dir:
            session_file = os.environ.get("PI_SESSION_FILE")
            if not session_file:
                _emit_status("output", error="No session file available")
                raise RuntimeError("No session - output artifacts unavailable")
            artifacts_dir = session_file.rsplit(".", 1)[0]  # Strip .jsonl extension
        if not Path(artifacts_dir).exists():
            _emit_status(
                "output", error="Artifacts directory not found", path=artifacts_dir
            )
            raise RuntimeError(f"No artifacts directory found: {artifacts_dir}")

        if not ids:
            _emit_status("output", error="No IDs provided")
            raise ValueError("At least one output ID is required")

        if query and (offset is not None or limit is not None):
            _emit_status("output", error="query cannot be combined with offset/limit")
            raise ValueError("query cannot be combined with offset/limit")

        results: list[dict] = []
        not_found: list[str] = []

View on GitHub (pinned to 9690622007)

Solutions

  1. Set PI_ARTIFACTS_DIR (or PI_SESSION_FILE) in the environment before running the code.
  2. Run the script through the eval harness so it injects the session env vars.
  3. When spawning subprocesses, pass the parent environment through instead of a fresh env.
  4. For local development, skip output() and write files to a known directory directly.

Example fix

# before
output(ids=["result"])
# after
import os
os.environ.setdefault("PI_ARTIFACTS_DIR", "/tmp/eval-artifacts")
output(ids=["result"])
Defensive patterns

Strategy: validation

Validate before calling

import os
if not (os.environ.get('PI_ARTIFACTS_DIR') or os.environ.get('PI_SESSION_FILE')):
    raise RuntimeError('output() requires PI_ARTIFACTS_DIR or PI_SESSION_FILE in the environment')

Type guard

def has_session_env(): return bool(os.environ.get('PI_ARTIFACTS_DIR') or os.environ.get('PI_SESSION_FILE'))

Try / catch

try:
    output(ids=['result'])
except RuntimeError as e:
    if 'No session' in str(e):
        # not running under the eval harness — persist locally instead
        write_local_artifact()
    else:
        raise

Prevention

When it happens

Trigger: Calling output(ids=...) in a Python process where the eval harness didn't inject PI_ARTIFACTS_DIR or PI_SESSION_FILE — e.g. running the script standalone, spawning a subprocess that doesn't inherit the env, or invoking output() from a non-session REPL.

Common situations: Executing prelude code directly with `python script.py` outside the agent; launching a subprocess with a scrubbed environment (env={}); running the same code locally during development without the harness.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/12ad0e03df1d85d6. Report an issue: GitHub.