AI-assisted report: this issue was investigated and written with help from an AI assistant. The observations below are based on local DB/API inspection; sensitive transcript content and local project paths have been intentionally omitted.
Summary
The OpenCode web UI repeatedly shows a 404 error:
NotFoundError: Message not found: msg_...
This can appear across multiple browsers/devices, and it can continue to appear even after opening a new session.
The root cause appears to be a logical DB inconsistency: an assistant message remains in the message table with parentID pointing to a user message that has been removed via a message.removed.1 event.
Environment
opencode version: 1.17.18
OS: Linux 7.0.0-27-generic x64
terminal: vscode 1.121.0 / xterm-256color
plugins: none
mode: opencode web --hostname 127.0.0.1 --port 4096
Affected historical sessions in the local DB included sessions created with versions 1.17.13 and 1.17.18.
Observed behavior
The web UI repeatedly displayed an error like:
Error: Message not found: msg_f4f9877d90013TMgCeYSd6VD56
body: {
"name": "NotFoundError",
"data": {
"message": "Message not found: msg_f4f9877d90013TMgCeYSd6VD56"
}
}
status: 404
The same error was reproducible through the local API:
GET /session/{sessionID}/message/{missingMessageID}
=> 404 {"name":"NotFoundError","data":{"message":"Message not found: ..."}}
But GET /session/{sessionID}/message still returned 200, so the session message list endpoint itself was not completely broken.
DB integrity checks
SQLite physical integrity looked OK:
PRAGMA quick_check; -- ok
PRAGMA integrity_check; -- ok
So this does not look like raw SQLite file corruption.
Logical inconsistency found
There were assistant messages whose parentID did not exist in the message table.
Sanitized detection query:
WITH parents AS (
SELECT id, session_id, json_extract(data, '$.parentID') AS parent_id
FROM message
WHERE json_extract(data, '$.parentID') IS NOT NULL
)
SELECT p.id AS child_message_id, p.session_id, p.parent_id AS missing_parent_id
FROM parents p
LEFT JOIN message m ON m.id = p.parent_id
WHERE m.id IS NULL;
In this local DB, it found 10 dangling parent references.
For the specific failing message ID, the event log still contained:
message.updated.1 -- for the removed user message
message.part.updated.1 -- for the text part of that user message
message.removed.1 -- removing that user message
But an assistant message still had:
{"parentID":"msg_f4f9877d90013TMgCeYSd6VD56", "role":"assistant", ...}
The removed parent message no longer existed in the message table, causing the API to return 404 when the UI attempted to resolve it.
Likely trigger
The affected rows were associated with abort/error/reconnect-like situations, including MessageAbortedError and APIError assistant messages.
This was observed across multiple model IDs in the local DB, including gpt-5.5, gpt-5.6, gpt-5.6-luna, and gpt-5.6-sol. It does not look strictly model-specific, although newer model/API behavior may make the race easier to trigger.
Workaround that fixed the local instance
Restoring the missing parent message rows and their part rows from the append-only event log made the API return 200 again for the previously missing message, and removed the repeated UI error.
After repair:
dangling parent references: 10 -> 0
orphan parts: 0
PRAGMA integrity_check: ok
GET /session/{sessionID}/message/{previouslyMissingMessageID}: 200
Expected behavior
One of the following would avoid the UI-breaking state:
message.removed should not leave child assistant messages with parentID pointing to a removed message.
- The API/UI should tolerate missing parent messages and render a placeholder instead of throwing a fatal 404.
- A migration/check/repair path could detect and fix dangling
parentID references.
Actual behavior
A removed user message can still be referenced by an assistant message's parentID, and the web UI repeatedly surfaces Message not found errors when it tries to resolve that parent message.
AI-assisted report: this issue was investigated and written with help from an AI assistant. The observations below are based on local DB/API inspection; sensitive transcript content and local project paths have been intentionally omitted.
Summary
The OpenCode web UI repeatedly shows a 404 error:
This can appear across multiple browsers/devices, and it can continue to appear even after opening a new session.
The root cause appears to be a logical DB inconsistency: an assistant message remains in the
messagetable withparentIDpointing to a user message that has been removed via amessage.removed.1event.Environment
Affected historical sessions in the local DB included sessions created with versions
1.17.13and1.17.18.Observed behavior
The web UI repeatedly displayed an error like:
The same error was reproducible through the local API:
But
GET /session/{sessionID}/messagestill returned200, so the session message list endpoint itself was not completely broken.DB integrity checks
SQLite physical integrity looked OK:
So this does not look like raw SQLite file corruption.
Logical inconsistency found
There were assistant messages whose
parentIDdid not exist in themessagetable.Sanitized detection query:
In this local DB, it found 10 dangling parent references.
For the specific failing message ID, the event log still contained:
But an assistant message still had:
{"parentID":"msg_f4f9877d90013TMgCeYSd6VD56", "role":"assistant", ...}The removed parent message no longer existed in the
messagetable, causing the API to return 404 when the UI attempted to resolve it.Likely trigger
The affected rows were associated with abort/error/reconnect-like situations, including
MessageAbortedErrorandAPIErrorassistant messages.This was observed across multiple model IDs in the local DB, including
gpt-5.5,gpt-5.6,gpt-5.6-luna, andgpt-5.6-sol. It does not look strictly model-specific, although newer model/API behavior may make the race easier to trigger.Workaround that fixed the local instance
Restoring the missing parent
messagerows and theirpartrows from the append-only event log made the API return 200 again for the previously missing message, and removed the repeated UI error.After repair:
Expected behavior
One of the following would avoid the UI-breaking state:
message.removedshould not leave child assistant messages withparentIDpointing to a removed message.parentIDreferences.Actual behavior
A removed user message can still be referenced by an assistant message's
parentID, and the web UI repeatedly surfacesMessage not founderrors when it tries to resolve that parent message.