ERROR: function min(vector) does not exist means you wrote min
or max over a pgvector column. The vector type has no ordering, so those
aggregates are not defined for it. Aggregate the thing you actually wanted, usually a
dimension count or a distance, which are plain numbers.
If the goal was "how wide are the embeddings", use
max(vector_dims(embedding)): vector_dims returns an integer per
row and max over integers is fine. If the goal was "the nearest chunk", do
not aggregate at all: order by the distance operator and take the first row.
The error
select d.slug, count(*), vector_dims(min(c.embedding))
from knowledge_chunk c join knowledge_document d on d.id = c.document_id
group by 1;
ERROR: function min(vector) does not exist
LINE 1: ...slug, count(*) as chunks, vector_dims(min(c.embedding)) ...
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Why it happens
PostgreSQL's min and max are defined per type, and they need a
type that can be ordered. Numbers, text and dates have an order; a 768-dimensional vector
does not, so pgvector defines no min(vector). It does define
avg and sum, because adding vectors and dividing by a count
means something. The hint about explicit type casts is the generic message PostgreSQL
prints when no overload matches, and it is misleading here: no cast will make a vector
orderable.
The fix
-- the dimension of the stored vectors, per document
select d.slug, count(*) as chunks, max(vector_dims(c.embedding)) as dims
from knowledge_chunk c join knowledge_document d on d.id = c.document_id
group by 1;
-- the nearest chunk to a query vector: no aggregate, just an ordered limit
select c.text, c.embedding <=> $1 as distance
from knowledge_chunk c
order by c.embedding <=> $1
limit 6;
Apply the scalar function to the column first, then aggregate the scalar. For nearest
neighbours, the pattern is order-by-distance with a limit, which is also what lets the
HNSW index do the work; an aggregate would force a full scan even if it existed. If you
really need one representative vector per group, avg(embedding) is defined
and gives the centroid, which is occasionally what a "min" was reaching for.
What the AI got wrong: it wrote the query for a screenshot in one go,
reached for min as a way to "pick any row's vector" for a dimension
check, and photographed the error. The second attempt moved vector_dims
inside the aggregate; the picture in Part 6 is that one.
Where it bit us
Season four, Part 6,
while proving the knowledge table's contents for the post. Nothing in the application was
affected; the EF Core query uses CosineDistance and an ordered
Take, which compiles to the second form above.
Frequently asked
- Which aggregates does pgvector support on a vector column?
- avg and sum, which produce a vector. min and max are not defined because vectors have no ordering. For anything else, apply a scalar function such as vector_dims or a distance operator first and aggregate the number.
- How do I check the dimension of embeddings stored in pgvector?
- Use vector_dims(embedding) per row and aggregate that, for example max(vector_dims(embedding)) grouped by document. The column's declared type, vector(768), also fixes the width for every row.
- How do I find the nearest vectors in pgvector without an aggregate?
- Order by the distance operator and limit: order by embedding <=> $1 limit 6 for cosine distance. That form uses the HNSW or IVFFlat index; aggregates would not.
More decoded errors in the Fixes category, or start the season that produced this one at Part 1.