MemPalace/mempalace · error · ValueError

event {event_id!r} not found

Error message

event {event_id!r} not found

What it means

ack_event(event_id=...) could not find an event with that id in the events table, so no acknowledgment can be created. The ack mechanism copies stream/room/correlation_id from the target event and routes back to its from_agent — with no target there is nothing to copy, hence the hard failure. The id is first normalized through _sanitize_routing (trim, length, control chars).

Source

Thrown at mempalace/logstream.py:595

        from_agent: str,
        status: str = None,
        body: str = "",
    ) -> dict:
        """Append an ``event.ack`` referencing a prior event.

        The target event is never mutated. The ack copies the target's
        stream/room, copies its ``correlation_id`` (falling back to the
        target's id so request/ack stay tied together), and routes back
        to the target's ``from_agent``.
        """
        event_id = _sanitize_routing(event_id, "event_id")
        with self._lock:
            conn = self._conn()
            target = conn.execute(
                "SELECT rowid, * FROM events WHERE id = ?", (event_id,)
            ).fetchone()
        if target is None:
            raise ValueError(f"event {event_id!r} not found")

        return self.append_event(
            type=ACK_EVENT_TYPE,
            stream=target["stream"],
            room=target["room"],
            from_agent=from_agent,
            to_agent=target["from_agent"],
            correlation_id=target["correlation_id"] or target["id"],
            status=status,
            body=body,
            metadata={"ack_of": event_id},
        )

    def submit_patch(
        self,
        content: str,
        from_agent: str,
        stream: str,

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Use the id exactly as returned: evt = ls.append_event(...) then later ls.ack_event(evt['id'], ...).
  2. Confirm the id exists first: ls.get_event(event_id) or ls.list_events(since_event_id=...) to see what is visible.
  3. Ensure producer and consumer open the same database file (same palace directory) — replication must deliver the original event before acking.

Example fix

// before
ls.ack_event("evt_20250814", from_agent="windows-codex")  # truncated id
// after
evt = ls.list_events(type="task.request", correlation_id="task_123")[0]
ls.ack_event(evt["id"], from_agent="windows-codex", body="started")
Defensive patterns

Strategy: try-catch

Validate before calling

def event_exists(ls, event_id) -> bool:
    try:
        return ls.get_event(event_id) is not None
    except ValueError:
        return False

if not event_exists(ls, target_id):
    raise LookupError(f"cannot ack unknown event {target_id!r}; not yet replicated?")

Try / catch

try:
    ack = ls.ack_event(event_id, from_agent=me, body=body)
except ValueError as e:
    if "not found" in str(e):
        # target not replicated/visible yet — schedule a retry after sync
        retry_later(event_id, from_agent=me, body=body)
    else:
        raise

Prevention

When it happens

Trigger: ack_event with a typo'd or truncated id string; acking an event that lives in a different db_path/palace directory; acking an event that was never appended (producer and consumer disagree on the exchange); passing rowid instead of the 'evt_...' string id.

Common situations: Multi-replica setups where the consumer's logstream has not yet replicated the original event; ids mangled through log truncation or clipboard copy; tests against a fresh in-memory Logstream without seeding the target event.

Related errors


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/2dc8ffc7612d9667. Report an issue: GitHub.