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
- Start an OpenCode session with OpenViking plugin enabled
- 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)
- Check plugin logs at `~/.config/opencode/plugins/openviking-memory.log`
- Observe: `Session map saved` with `count` decreased by 1 — session mapping deleted
- 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
Bug Description
When an OpenCode session encounters a
session.errorevent, any messages that are stored inpendingMessages(but not yet marked ascapturedMessages) are permanently lost. This is because the error handler only checkscapturedMessages.size > 0before deciding whether to commit, completely ignoringpendingMessages.Root Cause
In the OpenViking memory plugin (
openviking-memory.ts), thesession.errorevent 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 === 0butpendingMessages.size > 0, the code enters theelsebranch and deletes the entire session mapping, losing all pending messages that were actively being captured.Reproduction Steps
pendingMessagesbut not yetcapturedMessages), trigger asession.errorevent (e.g., force quit OpenCode or crash)Expected Behavior
When
session.erroroccurs, the plugin should check for ANY unsaved work: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
mapping.pendingCleanup = true
if (!mapping.commitInFlight) {
await startBackgroundCommit(mapping, sessionId, config)
}
}
```
Impact
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
Related Issues