Skip to content

[Bug] vec reindex crashes — ImportError: cannot import name 'sample_db_embedding_widths' from agentmemory.embeddings #160

Description

@J0nd1sk

Summary

brainctl vec reindex crashes immediately with an ImportError for every user. The command imports sample_db_embedding_widths from agentmemory.embeddings, but that function is not defined anywhere in the codebase.

This matters because vec reindex is the documented migration path when switching embedding models — pyproject.toml (the [vec] extra docstring) instructs: "When changing models on an existing brain.db, run brainctl vec reindex --model <name> to migrate the vector index." That path is currently dead.

Environment

  • brainctl main @ c634808 (version = "2.8.0"); also reproduces on the PyPI 2.8.0 wheel
  • brainctl[vec] installed, sqlite-vec present, Ollama reachable

Reproduction

brainctl init
brainctl memory add "the deploy key rotates every 90 days" --category ops
brainctl vec reindex

Result:

{
  "error": "ImportError: cannot import name 'sample_db_embedding_widths' from 'agentmemory.embeddings' (.../agentmemory/embeddings.py)"
}

Root cause

src/agentmemory/_impl.py:7855 (inside cmd_vec_reindex) imports the symbol:

from agentmemory.embeddings import (
    ...
    sample_db_embedding_widths,
    ...
)

and calls it at _impl.py:7873:

width_probe = sample_db_embedding_widths(db_vec, sample_size=8)

But grep -rn "def sample_db_embedding_widths" src returns nothing — the function is referenced but never implemented. The import is at the top of the function body, so the command fails before doing any work.

The surrounding comment (_impl.py:7868-7872, "audit H4") makes the intended contract clear: probe the actual byte width of a sample of stored embeddings and cross-check it against the dim declared in the vec_memories DDL, so the destructive DROP+CREATE refuses to run on a corrupted/mixed-width index unless --force is passed.

The callsite expects a dict with keys: ok, sample_count, consistent, declared_dim, observed_dims, message.

Suggested fix

Implement sample_db_embedding_widths(conn, sample_size=8) in embeddings.py next to get_db_embedding_dim. It should:

  • read up to sample_size rows from vec_memories (SELECT embedding ...),
  • compute each vector's float width as len(blob) // 4 (float32),
  • compare the observed width(s) against get_db_embedding_dim(conn),
  • return {"ok": False, "sample_count": 0, ...} when the table is absent/unreadable (so the reindex guard treats it as "nothing to check" and proceeds to build a fresh index),
  • return consistent=False only when sampled rows disagree with each other or with the declared dim.

I have a working implementation + unit tests and will open a PR.

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