Skip to content

Upgrade path 0.18.x → 0.27 fails: schema.sql tries to index content_chunks.search_vector before migration v26 adds the column #661

@Quato21

Description

@Quato21

What broke

Upgrading from a working v0.18.2 install (Supabase Postgres, schema_version=24, 0 pages) to v0.27.0:

$ git -C ~/gbrain checkout ee9ceb3   # v0.27 commit
$ bun install
$ gbrain apply-migrations --yes
...
NOTICE: relation "content_chunks" already exists, skipping
NOTICE: relation "idx_chunks_page_index" already exists, skipping
NOTICE: relation "idx_chunks_page" already exists, skipping
NOTICE: relation "idx_chunks_embedding" already exists, skipping
column "search_vector" does not exist
Phase A (schema) failed: Command failed: gbrain init --migrate-only. Aborting; re-run after fixing.
Migration v0.11.0 reported status=failed.

Root cause

src/schema.sql declares content_chunks.search_vector and indexes it in the same idempotent setup block:

  • L131: CREATE TABLE IF NOT EXISTS content_chunks ( ... search_vector TSVECTOR ... )
  • L141: CREATE INDEX IF NOT EXISTS idx_chunks_search_vector ON content_chunks USING GIN(search_vector);
  • L150–164: trigger that maintains search_vector on INSERT/UPDATE.

On a pre-v0.27 install, content_chunks already exists from old schema without search_vector. CREATE TABLE IF NOT EXISTS is a
no-op when the table exists, so the new column is never added. The next statement (CREATE INDEX ... USING GIN(search_vector))
fails because the column isn't there.

Migration v26 (content_chunks_code_metadata) is the path that's supposed to add search_vector to existing content_chunks, but it
runs after gbrain init --migrate-only (which executes schema.sql first). The schema-setup phase blows up before the migration
runner gets to v26.

The same pattern for pages.search_vector (L478–480) is fine because that one uses an explicit ALTER TABLE pages ADD COLUMN IF NOT EXISTS search_vector tsvector before the index. The fix is to apply the same ALTER TABLE ... IF NOT EXISTS pattern to
content_chunks.search_vector, OR to remove the column from schema.sql entirely and let migration v26 own it.

Repro

# Fresh v0.18.2 install
git clone https://github.com/garrytan/gbrain ~/gbrain-repro && cd ~/gbrain-repro
git checkout 08b3698   # v0.18.2
bun install && bun link
gbrain init --supabase --non-interactive --json   # against an empty Supabase project

# Upgrade
git checkout ee9ceb3   # v0.27.0 commit
bun install
gbrain apply-migrations --yes
# fails as shown above

Workaround used

Drop public-schema tables, run gbrain init --supabase --non-interactive --json clean. Brain had 0 pages so this was free; data-bearing
brains can't take this path.

Suggested fix

In src/schema.sql, replace the inline search_vector TSVECTOR column in the content_chunks CREATE TABLE with an explicit additive
step right after the table create:

CREATE TABLE IF NOT EXISTS content_chunks (
  -- ... existing columns ...
  -- (drop search_vector from the inline column list)
);

ALTER TABLE content_chunks ADD COLUMN IF NOT EXISTS search_vector TSVECTOR;
CREATE INDEX IF NOT EXISTS idx_chunks_search_vector ON content_chunks USING GIN(search_vector);

This matches what pages.search_vector already does at L478–480 and makes the schema setup idempotent on existing installs.

Environment

  • gbrain commits involved: 08b3698 (v0.18.2 baseline) → ee9ceb3 (v0.27.0)
  • engine: postgres (Supabase pooler)
  • macOS 25.4.0 / Bun 1.3.13
  • 0 pages at upgrade time (data-bearing brains likely hit this harder)

Side notes (not blockers — file separately if useful)

  • gbrain init --help doesn't print help; it falls through and runs init on PGLite. Works for most subcommands but not init.
  • gbrain init (no args) silently overwrites a Supabase config with a fresh PGLite one. Consider a confirm prompt or a guard when
    ~/.gbrain/config.json already declares engine: postgres.
  • gbrain upgrade calls bun update gbrain. For bun link installs (the path the README recommends) this is a no-op or wrong; git pull && bun install is the real upgrade. Worth a heads-up in runUpgrade() when detectInstallMethod() sees a linked clone.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions