Skip to content

HINDSIGHT_API_VECTOR_EXTENSION ignored by an earlier unconditional pgvector check in migrations.py #2423

Description

@swarthyplacebo

Summary

HINDSIGHT_API_VECTOR_EXTENSION is correctly read and reflected in the startup banner (Extensions: vchord (vector) / scann (vector)), but a separate, unconditional code path in migrations.py still attempts CREATE EXTENSION vector (pgvector) regardless of the configured backend, before the configured-extension dispatch logic ever gets a chance to run. This makes HINDSIGHT_API_VECTOR_EXTENSION unusable for vchord/scann on any host where the bundled pgvector binary itself fails to load (e.g. a glibc mismatch with pg0's pre-built vector.so).

Reproduction

export HINDSIGHT_API_VECTOR_EXTENSION=vchord
export HINDSIGHT_API_LLM_PROVIDER=ollama
export HINDSIGHT_API_LLM_MODEL=<any>
hindsight-api

Startup banner correctly shows:

Extensions: vchord (vector) / native (text)

But migration immediately fails:

pgvector extension is not installed and cannot be installed: (psycopg2.errors.UndefinedFile) could not load library ".../vector.so": ...
[SQL: CREATE EXTENSION vector]
RuntimeError: pgvector extension is required but not installed. Please install it with: CREATE EXTENSION vector;

Same result with HINDSIGHT_API_VECTOR_EXTENSION=scann.

Root cause (traced in hindsight-api-slim==0.7.2, also present in 0.8.3's source as downloaded from PyPI today)

hindsight_api/_vector_index.py has the correct, extension-aware dispatch table:

_EXTENSION_INSTALL_SQL = {
    "pgvector": ("CREATE EXTENSION IF NOT EXISTS vector",),
    "pgvectorscale": (
        "CREATE EXTENSION IF NOT EXISTS vector",
        "CREATE EXTENSION IF NOT EXISTS vectorscale CASCADE",
    ),
    "vchord": ("CREATE EXTENSION IF NOT EXISTS vchord CASCADE",),
    "scann": (
        "CREATE EXTENSION IF NOT EXISTS vector",
        "CREATE EXTENSION IF NOT EXISTS alloydb_scann CASCADE",
    ),
}

Correctly, vchord has no pgvector dependency.

But hindsight_api/migrations.py's run_migrations() contains an earlier, unconditional block (around line 270-330 in 0.7.2) that runs before os.getenv("HINDSIGHT_API_VECTOR_EXTENSION", ...) is ever read (that read only happens later, around line 339). This earlier block unconditionally checks for and tries to create the literal vector extension:

ext_check = conn.execute(text(
    "SELECT extname, nspname FROM pg_extension e "
    "JOIN pg_namespace n ON e.extnamespace = n.oid "
    "WHERE extname = 'vector'"
)).fetchone()
...
conn.execute(text("CREATE EXTENSION vector"))

This block has no branch on the configured vector backend at all, so it crashes the entire migration before _EXTENSION_INSTALL_SQL's correct, backend-aware logic (used elsewhere, e.g. ensure_vector_extension() at line ~595) ever runs.

Impact

Anyone trying to use a non-pgvector backend (vchord, scann, pgvectorscale) on a host where the bundled pg0 pgvector binary can't load for any reason (glibc mismatch is one concrete case — Debian 12's glibc 2.36 vs. a vector.so requiring 2.38) cannot start Hindsight at all, even though they've explicitly configured a backend that doesn't need pgvector.

Suggested fix

Gate the early unconditional pgvector check/install block on configured_vector_extension() == "pgvector" (or move it after the HINDSIGHT_API_VECTOR_EXTENSION read at line 339, reusing the existing _EXTENSION_INSTALL_SQL dispatch instead of a separate hardcoded check).

Environment

  • hindsight-api-slim 0.7.2 (installed), confirmed same logic present in 0.8.3 source from PyPI
  • Embedded pg0 PostgreSQL 18.1.0, Debian 12 (glibc 2.36) host
  • pg0's bundled vector.so requires GLIBC_2.38, which is the proximate trigger, but the real bug is that no HINDSIGHT_API_VECTOR_EXTENSION value avoids this code path

Happy to provide more logs or test a patch.

Filed with the help of Sally Sonnet.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions