fix: detach user_memories before DELETE FROM metabots to avoid FOREIGN KEY constraint failed - #6
Open
WuFenG-Hub wants to merge 1 commit into
Open
Conversation
…urface delete errors deleteMetabot deleted the metabots row while user_memories.metabot_id still referenced it. The column is a bare REFERENCES (NO ACTION) and PRAGMA foreign_keys=ON is forced on every connection, so the DELETE was rejected with FOREIGN KEY constraint failed (19) for any bot that had memories (or metaid_knowledge_entries rows, whose metabot_id is NOT NULL). The renderer kept the delete modal open with the error hidden behind it, so a failed delete appeared to do nothing. - Null user_memories.metabot_id before the DELETE so memory rows survive the bot as history (matching the original no-cascade intent). - Delete the bot's metaid_knowledge_entries rows (metabot_id is NOT NULL; best-effort for the SDK-managed table). - Surface delete failures via toast instead of hiding them behind the modal. - Add regression tests covering deletion with attached memories under foreign_keys=ON (rows preserved with metabot_id nulled), the raw DELETE rejection, the knowledge-entries cleanup, and the missing-id no-op.
WuFenG-Hub
force-pushed
the
fix/delete-metabot-fk
branch
from
August 13, 2026 03:20
75e0540 to
b8f9c63
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Deleting any bot that has stored memories fails with
FOREIGN KEY constraint failed (19).Root cause chain:
user_memories.metabot_id INTEGER REFERENCES metabots(id)has noON DELETEclause (SQLite default is NO ACTION — the parent row cannot be deleted while child rows reference it). Defined atsrc/main/sqliteStore.ts:351(CREATE TABLE) andsrc/main/sqliteStore.ts:1456/src/main/coworkStore.ts:1153(ALTER TABLE migrations).PRAGMA foreign_keys = ON(src/main/nativeSqliteDatabase.ts:58), so the constraint is actually enforced.deleteMetabot(src/main/metabotStore.ts) only ranUPDATE metabots SET boss_id = NULLandDELETE FROM metabots WHERE id = ?, never releasinguser_memories.metabot_id. Its comment says it deliberately does not cascadeuser_memoriesto preserve history — which directly conflicts with the NO ACTION FK, so the delete is rejected by the database.Reproduction: with
PRAGMA foreign_keys=ON,DELETE FROM metabots WHERE id = <bot-with-memories>fails; clearing the memory references first makes the delete succeed.cowork_sessionsandmetabot_memory_policiesareON DELETE CASCADEand are not blockers.Fix
In
deleteMetabot, beforeDELETE FROM metabots, run:This detaches memory rows from the deleted bot instead of cascading them — preserving the original intent (experience data survives the bot itself) while satisfying the enforced FK.
boss_idcleanup is unchanged.Chosen as an application-layer fix to avoid a high-cost table rebuild migration; a schema-level
ON DELETE SET NULLcould be evaluated separately.Verification
tests/metabotDeleteWithMemories.test.mjs,node --test.mjs pattern):deleteMetaboton a bot with 2 attached memories succeeds underforeign_keys=ON; memory rows survive withmetabot_idset toNULL; bot row is gone.DELETE FROM metabotswith an attached memory is rejected (FOREIGN KEY constraint failed) — proving the constraint is enforced and the fix is required.false.node --test tests/metabotDeleteWithMemories.test.mjs→ 3 pass / 0 fail.npx -p typescript@5.9.3 tsc --project electron-tsconfig.json— error set identical before/after this change (zero new errors; remaining errors are pre-existing, in unrelated files).os.tmpdir()only.metabotAccountService.test.mjs(wrong require pathdist-electron/services/...instead ofdist-electron/main/services/...; reproduced without this change).Update (2026-08-13)
The fix is consolidated and extended on top of the latest
main(0.4.6):metaid_knowledge_entriescleanup: this SDK-managed table also referencesmetabots(id)with NO ACTION, and itsmetabot_idcolumn isNOT NULL— so a bot with knowledge rows hit the same failure.deleteMetabotnow deletes the bot's knowledge rows (best-effort, guarded for installs where the SDK table is absent).actionErrorbehind the overlay, so it looked like the delete did nothing.handleDeleteConfirmnow closes the modal and shows the real error via toast (both for failed IPC results and thrown errors), preserving the existing edit-view fallback.metaid_knowledge_entriescleanup underforeign_keys=ON(4 tests, all pass).