fix(core): tolerate missing vec0 module during project delete

On Windows SQLite CI the embeddings cleanup hits

  sqlite3.OperationalError: no such module: vec0
  [SQL: DELETE FROM search_vector_embeddings WHERE rowid IN (...)]

because the sqlite-vec extension isn't loaded into the connection
(some Windows Python builds don't expose enable_load_extension on
sqlite3.Connection — see #711). The vec0 virtual table is registered
in sqlite_master, so the table-existence check passes, but any access
to it fails until the module is loaded.

If vec0 isn't loadable, semantic search was never able to write
embeddings, so there's nothing to clean up. Wrap the embeddings DELETE
in a try/except that swallows OperationalError for vec0 and logs a
debug line — the chunk DELETE below still runs.

The KeyError from test_mcp_sse_forces_local on 3.14 SQLite is an
unrelated transient — same code passes on 3.12/3.13 SQLite, Postgres
3.14, and locally on Python 3.14. Will let CI re-run after this push.

Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
phernandez
2026-05-16 15:53:49 -05:00
parent d3619f97f9
commit 43c50ea683
@@ -4,8 +4,9 @@ from pathlib import Path
from typing import Optional, Sequence, Union
from loguru import logger
from sqlalchemy import inspect as sa_inspect, select, text
from sqlalchemy.exc import NoResultFound
from sqlalchemy.exc import NoResultFound, OperationalError
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
from basic_memory import db
@@ -175,14 +176,31 @@ class ProjectRepository(Repository[Project]):
# we delete the chunk rows below.
if "search_vector_chunks" in existing_tables:
if is_sqlite and "search_vector_embeddings" in existing_tables:
await session.execute(
text(
"DELETE FROM search_vector_embeddings WHERE rowid IN ("
"SELECT id FROM search_vector_chunks "
"WHERE project_id = :project_id)"
),
{"project_id": entity_id},
)
try:
await session.execute(
text(
"DELETE FROM search_vector_embeddings WHERE rowid IN ("
"SELECT id FROM search_vector_chunks "
"WHERE project_id = :project_id)"
),
{"project_id": entity_id},
)
except OperationalError as exc:
# Trigger: the vec0 SQLite extension isn't loaded into this
# connection — common on Windows builds where
# enable_load_extension is unavailable (#711).
# Why: the embeddings table is registered as a vec0 virtual
# table, so any access (even a DELETE) needs the module
# loaded. If it isn't, no row was ever inserted either, so
# there's nothing to leak.
# Outcome: log and continue — the chunk DELETE below still
# runs, and the absence of vec0 means no orphan vectors.
if "vec0" not in str(exc):
raise
logger.debug(
"Skipping search_vector_embeddings purge: vec0 "
"extension not loaded on this connection"
)
await session.execute(
text("DELETE FROM search_vector_chunks WHERE project_id = :project_id"),
{"project_id": entity_id},