{"record":{"id":"15591dffb6e4e04e","repo":"MemPalace/mempalace","slug":"artifact-ids-references-unknown-artifact-artifact","errorCode":null,"errorMessage":"artifact_ids references unknown artifact {artifact_id!r}","messagePattern":"artifact_ids references unknown artifact (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mempalace/logstream.py","lineNumber":439,"sourceCode":"        if not isinstance(artifact_ids, list) or not all(\n            isinstance(a, str) and a for a in artifact_ids\n        ):\n            raise ValueError(\"artifact_ids must be a list of artifact id strings\")\n        artifact_ids = list(dict.fromkeys(artifact_ids))  # dedup, keep order\n\n        event_id = _new_id(\"evt\")\n        created_at = _utc_now_iso()\n        hlc = self._clock.tick()\n\n        with self._lock:\n            conn = self._conn()\n            with conn:\n                for artifact_id in artifact_ids:\n                    found = conn.execute(\n                        \"SELECT 1 FROM artifacts WHERE id = ?\", (artifact_id,)\n                    ).fetchone()\n                    if not found:\n                        raise ValueError(\n                            f\"artifact_ids references unknown artifact {artifact_id!r}\"\n                        )\n                cursor = conn.execute(\n                    \"INSERT INTO events (id, type, stream, room, from_agent, to_agent,\"\n                    \" correlation_id, branch, base_commit, status, body, created_at,\"\n                    \" metadata_json, origin_replica, hlc)\"\n                    \" VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\",\n                    (\n                        event_id,\n                        type,\n                        stream,\n                        room,\n                        from_agent,\n                        to_agent,\n                        correlation_id,\n                        branch,\n                        base_commit,\n                        status,","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/logstream.py#L421-L457","documentation":"An id in artifact_ids does not exist in the artifacts table, so the event insert is rolled back. append_event validates referential integrity inside the same transaction — every referenced artifact must have been created first via put_artifact on the same Logstream database. The check runs per-id in insertion order and reports the first missing one.","triggerScenarios":"append_event(artifact_ids=['art_...']) before put_artifact created it; a typo or truncated id; referencing an artifact written to a different db_path (another palace directory or replica); the artifact insert committed to a different database file after a path/config change.","commonSituations":"Producer/consumer ordering bugs where the event is appended before the artifact upload; multi-replica setups where an event referencing a remote artifact is applied before that artifact replicates; palace directory changed between calls.","solutions":["Create the artifact first: art = ls.put_artifact(...) then append_event(artifact_ids=[art['id']]).","Verify existence with ls.get_artifact(aid) before appending and create it if missing.","Confirm every writer/reader uses the same db_path — a stray logstream.sqlite3 elsewhere means the lookup runs against the wrong file."],"exampleFix":"// before\nevt = ls.append_event(type=\"patch.ready\", artifact_ids=[\"art_20250814_deadbeef\"], ...)\n// after\nart = ls.put_artifact(kind=\"patch\", content=diff_text, created_by=\"mac-codex\")\nevt = ls.append_event(type=\"patch.ready\", artifact_ids=[art[\"id\"]], ...)","handlingStrategy":"validation","validationCode":"def ensure_artifacts(ls, ids):\n    missing = []\n    for aid in ids:\n        if ls.get_artifact(aid) is None:\n            missing.append(aid)\n    return missing  # empty means safe to append\n\nmissing = ensure_artifacts(ls, artifact_ids)\nif missing:\n    raise RuntimeError(f\"artifacts not yet present: {missing}\")","typeGuard":null,"tryCatchPattern":"try:\n    evt = ls.append_event(..., artifact_ids=artifact_ids)\nexcept ValueError as e:\n    if \"unknown artifact\" in str(e):\n        # artifact not replicated/created yet; retry after sync\n        time.sleep(poll_s)\n        evt = ls.append_event(..., artifact_ids=artifact_ids)\n    else:\n        raise","preventionTips":["Order operations: put_artifact first, capture its returned id, then append_event referencing it.","In replicated setups, only reference artifacts that arrived with the same sync batch.","Log the exact artifact id at creation so mismatches are debuggable."],"tags":["logstream","referential-integrity","artifact","ordering"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}