Skip to content

[Bug] session.error handler loses pending messages when no captured messages exist #2093

@sacrtap

Description

@sacrtap

Bug Description

When an OpenCode session encounters a session.error event, any messages that are stored in pendingMessages (but not yet marked as capturedMessages) are permanently lost. This is because the error handler only checks capturedMessages.size > 0 before deciding whether to commit, completely ignoring pendingMessages.

Root Cause

In the OpenViking memory plugin (openviking-memory.ts), the session.error event handler at lines 1848-1857:

```typescript
// BEFORE (buggy code)
if (mapping.capturedMessages.size > 0 || mapping.commitInFlight) {
mapping.pendingCleanup = true
if (!mapping.commitInFlight) {
await startBackgroundCommit(mapping, sessionId, config)
}
} else {
// BUG: Deletes session mapping even when pendingMessages exist!
sessionMap.delete(sessionId)
sessionMessageBuffer.delete(sessionId)
await saveSessionMap()
}
```

Problem: When capturedMessages.size === 0 but pendingMessages.size > 0, the code enters the else branch and deletes the entire session mapping, losing all pending messages that were actively being captured.

Reproduction Steps

  1. Start an OpenCode session with OpenViking plugin enabled
  2. During an assistant message response (when content is in pendingMessages but not yet capturedMessages), trigger a session.error event (e.g., force quit OpenCode or crash)
  3. Check plugin logs at `~/.config/opencode/plugins/openviking-memory.log`
  4. Observe: `Session map saved` with `count` decreased by 1 — session mapping deleted
  5. All pending messages are lost, no commit is triggered

Expected Behavior

When session.error occurs, the plugin should check for ANY unsaved work:

  • `capturedMessages.size > 0`
  • `pendingMessages.size > 0` ← Missing check
  • `commitInFlight === true`

If any of these are true, the plugin should trigger a commit to preserve the work.

Actual Behavior

Only `capturedMessages` and `commitInFlight` are checked. Pending messages (which contain the actively-streaming assistant response) are ignored, and the session mapping is deleted.

Fix

Add `pendingMessages.size > 0` to the condition check:

```diff

  • if (mapping.capturedMessages.size > 0 || mapping.commitInFlight) {
  • // Check if there's any work to commit: captured messages, pending messages, or in-flight commit
  • if (mapping.capturedMessages.size > 0 || mapping.pendingMessages.size > 0 || mapping.commitInFlight) {
    mapping.pendingCleanup = true
    if (!mapping.commitInFlight) {
    await startBackgroundCommit(mapping, sessionId, config)
    }
    }
    ```

Impact

Scenario Before Fix After Fix
`session.error` with pending messages only ❌ Session mapping deleted, messages lost ✅ Commit triggered, messages preserved
Abnormal session termination ❌ Incomplete memory extraction ✅ Best-effort memory preservation

Evidence from Production Logs

Real-world session data showing the bug in action:

```
[2026-05-17T16:01:13.762Z] ERROR: OpenCode session error (session: ses_1c958bc0effe...)
[2026-05-17T16:01:13.763Z] INFO: Attempting to commit session after error
[2026-05-17T16:01:13.775Z] DEBUG: Message content stored as pending
[2026-05-17T16:01:26.684Z] DEBUG: Message buffered (no session mapping yet) ← Session mapping deleted!
[2026-05-17T16:01:55.742Z] DEBUG: Message buffered (no session mapping yet)
[2026-05-17T16:02:46.894Z] DEBUG: Message content buffered (no session mapping yet)
... (all subsequent messages buffered indefinitely, never committed)
```

Environment

  • OpenCode version: 1.15.3
  • OpenViking plugin: openviking-memory.ts (memory plugin)
  • OpenViking server: localhost:1933
  • OS: macOS

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions