{"record":{"id":"68b307f53f768d0d","repo":"google-gemini/gemini-cli","slug":"unknown-eventid-options-eventid","errorCode":null,"errorMessage":"Unknown eventId: ${options.eventId}","messagePattern":"Unknown eventId: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/agent/agent-session.ts","lineNumber":130,"sourceCode":"      }\n\n      queueVisibleEvent(event);\n\n      const currentResolve = resolve;\n      next = new Promise<void>((r) => {\n        resolve = r;\n      });\n      currentResolve?.();\n    });\n\n    try {\n      const currentEvents = this._protocol.events;\n      let replayStartIndex = -1;\n\n      if (options.eventId) {\n        const index = currentEvents.findIndex((e) => e.id === options.eventId);\n        if (index === -1) {\n          throw new Error(`Unknown eventId: ${options.eventId}`);\n        }\n\n        const resumeEvent = currentEvents[index];\n        trackedStreamId = resumeEvent.streamId;\n        const firstAgentStartIndex = currentEvents.findIndex(\n          (event) =>\n            event.type === 'agent_start' && event.streamId === trackedStreamId,\n        );\n\n        if (resumeEvent.type === 'agent_end') {\n          replayStartIndex = index + 1;\n          agentActivityStarted = true;\n          done = true;\n        } else if (\n          firstAgentStartIndex !== -1 &&\n          firstAgentStartIndex <= index\n        ) {\n          replayStartIndex = index + 1;","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/core/src/agent/agent-session.ts#L112-L148","documentation":"Thrown by the resume-by-eventId logic in the agent session when the caller passes an `options.eventId` that does not match any event in the in-memory `this._protocol.events` log. The lookup uses `findIndex` over recorded event ids; a -1 result means the cursor the consumer is asking to resume from is unknown to this session — typically because it belongs to a different session, was pruned, or was never persisted.","triggerScenarios":"Calling `send` (or equivalent resume entry) with `options.eventId` set to a value not present in the current session's event history. Common with cross-session replay, after a session restart that did not reload the event log, or when a caller serializes an event id from one process and replays it in another.","commonSituations":"Persisting an event id to a database and resuming in a new process that did not rehydrate `_protocol.events`; passing a client-generated id instead of the server-issued event id; trimming old events then resuming from a trimmed id; typo or copy-paste error in the id.","solutions":["Verify the eventId was issued by *this* session instance — check it against `session.events` before calling resume.","If resuming across processes, rehydrate the event log (or use `options.streamId` instead, which the resume flow can resolve to `agent_start`).","Confirm the id is the raw server value and not a wrapped/quoted form.","If the event was pruned, fall back to resuming by `streamId` or by starting a new stream."],"exampleFix":"// before\nawait session.send({ eventId: staleIdFromAnotherProcess });\n\n// after\nconst known = session.events.some((e) => e.id === candidateId);\nif (!known) {\n  await session.send({ streamId: lastStreamId });\n} else {\n  await session.send({ eventId: candidateId });\n}","handlingStrategy":"validation","validationCode":"function assertEventKnown(session: { events: { id?: string }[] }, eventId?: string) {\n  if (eventId && !session.events.some((e) => e.id === eventId)) {\n    throw new Error(`eventId ${eventId} not in this session's history`);\n  }\n}\n\nassertEventKnown(session, options?.eventId);","typeGuard":"function isKnownEventId(session: { events: { id?: string }[] }, id?: string): boolean {\n  return !id || session.events.some((e) => e.id === id);\n}","tryCatchPattern":"try {\n  await session.send({ eventId });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Unknown eventId')) {\n    // fall back to resuming by streamId, or start fresh\n    await session.send({ streamId: lastStreamId });\n    return;\n  }\n  throw e;\n}","preventionTips":["Only persist event ids that you can also rehydrate into the same session instance.","Prefer streamId-based resume across process boundaries; eventId is for in-session replay.","Before resuming, snapshot and confirm the event is still in history."],"tags":["agent-session","resume","validation","event-sourcing"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}