From 88dfbd26f42c9469ab4e71099ab7fcb979acf93f Mon Sep 17 00:00:00 2001 From: Scott Reimers Date: Thu, 23 Apr 2026 00:00:06 -0400 Subject: [PATCH] Fix: idx_group_keys_root migration creates index on missing column MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Phase 2f `canonical_root_post_id` column was added to both the CREATE TABLE block (for fresh DBs) and a conditional ALTER TABLE (for upgrading DBs). The matching CREATE INDEX, however, was inlined in the CREATE TABLE block — which runs BEFORE the ALTER. On an upgrading DB with the v0.6.1 schema, CREATE TABLE IF NOT EXISTS is a no-op against the existing (old) table, so the table still lacks the column when the index statement runs and SQLite bails with "Error code 1: SQL error or missing database" at offset 74. Caught on the v0.6.2 anchor deploy — the anchor died right after start because its v0.6.1 DB couldn't apply migrations. Fix: remove the index from the CREATE TABLE block; run an unconditional `CREATE INDEX IF NOT EXISTS idx_group_keys_root ...` in the migration section, after the conditional ALTER has added the column. Idempotent in both paths — fresh DB (column from CREATE TABLE) and upgrading DB (column from ALTER). 121 / 121 core tests pass. --- crates/core/src/storage.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/crates/core/src/storage.rs b/crates/core/src/storage.rs index 171758c..1500d02 100644 --- a/crates/core/src/storage.rs +++ b/crates/core/src/storage.rs @@ -287,7 +287,10 @@ impl Storage { canonical_root_post_id BLOB ); CREATE INDEX IF NOT EXISTS idx_group_keys_circle ON group_keys(circle_name); - CREATE INDEX IF NOT EXISTS idx_group_keys_root ON group_keys(canonical_root_post_id); + -- idx_group_keys_root is created in the migration block below, after + -- ALTER TABLE has ensured the canonical_root_post_id column exists + -- on upgraded DBs (CREATE TABLE IF NOT EXISTS is a no-op against an + -- older schema, so the column may still be missing at this point). CREATE TABLE IF NOT EXISTS group_member_keys ( group_id BLOB NOT NULL, member BLOB NOT NULL, @@ -658,10 +661,18 @@ impl Storage { )?.query_row([], |row| row.get::<_, i64>(0))?; if has_canonical_root == 0 { self.conn.execute_batch( - "ALTER TABLE group_keys ADD COLUMN canonical_root_post_id BLOB DEFAULT NULL; - CREATE INDEX IF NOT EXISTS idx_group_keys_root ON group_keys(canonical_root_post_id);" + "ALTER TABLE group_keys ADD COLUMN canonical_root_post_id BLOB DEFAULT NULL;" )?; } + // Ensure the root-lookup index exists on every startup. IF NOT EXISTS + // makes this idempotent; runs for both fresh DBs (where CREATE TABLE + // above populated the column) and just-upgraded DBs (where the ALTER + // above did). Before this fix, the index was inlined in the CREATE + // TABLE block and tried to reference a column that didn't exist yet + // on upgrading DBs. + self.conn.execute_batch( + "CREATE INDEX IF NOT EXISTS idx_group_keys_root ON group_keys(canonical_root_post_id);" + )?; // Add device_role column to peers if missing (Active CDN replication) let has_device_role = self.conn.prepare(