{"record":{"id":"24110100e0f9d4e5","repo":"can1357/oh-my-pi","slug":"no-artifacts-directory-found-artifacts-dir","errorCode":null,"errorMessage":"No artifacts directory found: {artifacts_dir}","messagePattern":"No artifacts directory found: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/eval/py/prelude.py","lineNumber":187,"sourceCode":"            output('scout_0', query='.files[0]')  # Extract JSON field\n            output('scout_0', offset=10, limit=20)  # Lines 10-29\n            output('scout_0', 'reviewer_1')  # Read multiple outputs\n        \"\"\"\n        # Prefer PI_ARTIFACTS_DIR so subagents resolve through the parent's\n        # shared artifacts dir; fall back to deriving from PI_SESSION_FILE\n        # for legacy callers / top-level sessions where the two coincide.\n        artifacts_dir = os.environ.get(\"PI_ARTIFACTS_DIR\")\n        if not artifacts_dir:\n            session_file = os.environ.get(\"PI_SESSION_FILE\")\n            if not session_file:\n                _emit_status(\"output\", error=\"No session file available\")\n                raise RuntimeError(\"No session - output artifacts unavailable\")\n            artifacts_dir = session_file.rsplit(\".\", 1)[0]  # Strip .jsonl extension\n        if not Path(artifacts_dir).exists():\n            _emit_status(\n                \"output\", error=\"Artifacts directory not found\", path=artifacts_dir\n            )\n            raise RuntimeError(f\"No artifacts directory found: {artifacts_dir}\")\n\n        if not ids:\n            _emit_status(\"output\", error=\"No IDs provided\")\n            raise ValueError(\"At least one output ID is required\")\n\n        if query and (offset is not None or limit is not None):\n            _emit_status(\"output\", error=\"query cannot be combined with offset/limit\")\n            raise ValueError(\"query cannot be combined with offset/limit\")\n\n        results: list[dict] = []\n        not_found: list[str] = []\n\n        for output_id in ids:\n            output_path = Path(artifacts_dir) / f\"{output_id}.md\"\n            if not output_path.exists():\n                not_found.append(output_id)\n                continue\n","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/eval/py/prelude.py#L169-L205","documentation":"output() resolves the artifacts directory (from PI_ARTIFACTS_DIR or PI_SESSION_FILE) and requires that the directory already exist on disk; if it doesn't, it emits an error status and raises RuntimeError 'No artifacts directory found: <path>'. The harness is expected to have created the directory when the session started — output() never creates it implicitly.","triggerScenarios":"PI_ARTIFACTS_DIR pointing at a deleted/never-created directory, PI_SESSION_FILE set to a path whose sibling artifacts dir (session path minus .jsonl) was cleaned up, a stale env var left over from a previous session, or a typo in the configured path.","commonSituations":"Re-running a script after tmp cleanup removed the artifacts dir; copying PI_SESSION_FILE/PI_ARTIFACTS_DIR between machines or containers; resuming an old session file whose artifacts directory was garbage-collected.","solutions":["Create the directory before calling output(): os.makedirs(artifacts_dir, exist_ok=True).","Point PI_ARTIFACTS_DIR at a directory that exists for the current session.","If PI_SESSION_FILE was moved/renamed, ensure the sibling artifacts directory matches its new path.","Re-run through the harness so it recreates the session's artifacts directory."],"exampleFix":"# before\noutput(ids=[\"result\"])  # artifacts dir cleaned up\n# after\nimport os\nartifacts = os.environ[\"PI_ARTIFACTS_DIR\"]\nos.makedirs(artifacts, exist_ok=True)\noutput(ids=[\"result\"])","handlingStrategy":"validation","validationCode":"import os\nfrom pathlib import Path\ndir_ = os.environ.get('PI_ARTIFACTS_DIR') or os.environ.get('PI_SESSION_FILE', '').rsplit('.', 1)[0]\nif dir_ and not Path(dir_).exists():\n    os.makedirs(dir_, exist_ok=True)","typeGuard":"def artifacts_ready():\n    d = os.environ.get('PI_ARTIFACTS_DIR') or os.environ.get('PI_SESSION_FILE', '').rsplit('.', 1)[0]\n    return bool(d) and Path(d).is_dir()","tryCatchPattern":"try:\n    output(ids=['result'])\nexcept RuntimeError as e:\n    if str(e).startswith('No artifacts directory found'):\n        os.makedirs(e.args[0].rsplit(': ', 1)[-1], exist_ok=True)\n        output(ids=['result'])\n    else:\n        raise","preventionTips":["Create PI_ARTIFACTS_DIR during session setup, before any cell runs.","If you move or rename PI_SESSION_FILE, move the sibling artifacts directory too.","Avoid tmp-dir cleanup jobs that delete live session artifacts.","Call os.makedirs(dir, exist_ok=True) defensively before output()."],"tags":["python","filesystem","artifacts","session"],"backgroundTag":"directory-not-found","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}