1. Home
  2. Troubleshooting
Help · error reference

pgvector troubleshooting

Paste your error into search (⌘K) or scan the index below. Every message on this page was reproduced on PostgreSQL 18.6 with pgvector 0.8.7 — the output is copied from the terminal, not paraphrased.

Tested on pgvector 0.8.7 · PostgreSQL 18.6Updated 2026-10-2717 min read

Error index#

Jump straight to the message you're seeing.

Message (or symptom)Usual cause
extension "vector" is not availablePackage not installed for this Postgres
permission denied to create extension "vector"Not a superuser
type "vector" does not existExtension enabled in another database or schema
expected 1536 dimensions, not 768Wrong embedding model or truncated vector
different vector dimensions 3 and 2Comparing vectors of different lengths
operator does not exist: vector <-> textDriver sends the parameter as text
NaN not allowed in vectorBad values from the embedding pipeline
"70000" is out of range for type halfvecValue above 65,504 cast to half precision
column cannot have more than 2000 dimensions for hnsw index3,072-dim (or larger) embeddings
column cannot have more than 4000 dimensionshalfvec limit
column does not have dimensionsColumn declared as vector without a size
ef_construction must be greater than or equal to 2 * mIndex options out of proportion
value 200 out of bounds for option "m"Option outside its allowed range
2000 is outside the valid range for parameter "hnsw.ef_search"ef_search maxes out at 1,000
invalid value for parameter "ivfflat.iterative_scan"strict_order is HNSW-only
memory required is 6 MB, maintenance_work_mem is 1 MBIVFFlat build needs more memory
hnsw graph no longer fits into maintenance_work_memHNSW build spilling to disk
ivfflat index created with little dataIVFFlat built on an empty or tiny table
could not resize shared memory segmentDocker's 64 MB /dev/shm
version "0.8.7" of extension "vector" is already installedUpgrade files not on the server
Symptom: index isn't used (Seq Scan)Operator, ordering or LIMIT mismatch
Symptom: fewer rows than LIMITFilter applied after the index scan
Symptom: results are "wrong" or missing obvious matchesRecall too low for your ef_search / probes
Symptom: index build takes foreverLow maintenance_work_mem; parallel workers never launched (TOAST)
Build errors (postgres.h, Illegal instruction, Windows)Compiling from source

Installation and setup#

extension "vector" is not available#

outputPostgreSQL 16 on a machine where only the PostgreSQL 18 package was installed
ERROR:  extension "vector" is not available
DETAIL:  Could not open extension control file "/usr/share/postgresql/16/extension/vector.control": No such file or directory.
HINT:  The extension must first be installed on the system where PostgreSQL is running.

Cause. The server you're connected to has no vector.control file. pgvector is compiled per Postgres major, so postgresql-18-pgvector does nothing for a version 16 server. The DETAIL line names the exact directory the server searched — compare it with where you installed.

Fix. Check SHOW server_version; and install the matching package (postgresql-16-pgvector, pgvector_16, …). In Docker, use the pgvector/pgvector image instead of postgres. On a managed service, the provider must offer it — see provider versions.

permission denied to create extension "vector"#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# SET ROLE app_user;
SET

demo=# CREATE EXTENSION vector;
ERROR:  permission denied to create extension "vector"
HINT:  Must be superuser to create this extension.

demo=# RESET ROLE;
RESET

Cause. pgvector's control file doesn't mark it trusted, so only superusers can create it. Fix. Have a superuser (or your provider's admin role) run CREATE EXTENSION vector; once in the database. Application roles don't need any special privilege to use the type afterwards.

type "vector" does not exist#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# \c other
You are now connected to database "other" as user "postgres".

other=# CREATE TABLE t (embedding vector(3));
ERROR:  type "vector" does not exist
LINE 1: CREATE TABLE t (embedding vector(3));
                                  ^

other=# \c demo
You are now connected to database "demo" as user "postgres".

Cause. Extensions are per database. Here it was created in demo but used in other. The same error appears when the extension lives in a schema that isn't on the search_path — Supabase installs it in extensions, for example. Fix. CREATE EXTENSION vector; in this database, or reference the type with its schema (extensions.vector(1536)), or add the schema to search_path.

version "0.8.7" of extension "vector" is already installed#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# ALTER EXTENSION vector UPDATE;
NOTICE:  version "0.8.7" of extension "vector" is already installed
ALTER EXTENSION

This NOTICE is harmless when you really are current. If you expected an upgrade, the server still has the old files on disk: the new package was installed for a different Postgres major, the container wasn't recreated from the new image, or make install used the wrong pg_config. Compare SELECT default_version FROM pg_available_extensions WHERE name = 'vector'; with the version you think you installed.

Inserting and querying vectors#

expected 1536 dimensions, not 768#

psqlInserting a 2-dimensional vector into a vector(3) column
demo=# INSERT INTO items (embedding) VALUES ('[1,2]');
ERROR:  expected 3 dimensions, not 2

Cause. A typed column such as vector(1536) only accepts exactly that many dimensions. In practice this means the embedding came from a different model than the column was designed for (e.g. text-embedding-3-small at 1,536 vs nomic-embed-text at 768), or a client passed a dimensions parameter.

Fix. Make every writer use the same model and dimension. If you deliberately store several models, use one column per model, or an untyped vector column with a model_id and per-model expression indexes (pattern here). To find the offending rows: SELECT vector_dims(embedding), count(*) FROM items GROUP BY 1;

different vector dimensions 3 and 2#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# SELECT '[1,2,3]'::vector <-> '[1,2]'::vector;
ERROR:  different vector dimensions 3 and 2

The same problem at query time: the query vector doesn't match the stored vectors. Usually the query was embedded with another model than the documents. A related message appears when casting: expected 3 dimensions, not 4.

operator does not exist: vector <-> text#

psqlA parameter typed as text (left) and with an explicit cast (right)
demo=# PREPARE q(text) AS SELECT id FROM items ORDER BY embedding <-> $1 LIMIT 5;
ERROR:  operator does not exist: vector <-> text
LINE 1: ...(text) AS SELECT id FROM items ORDER BY embedding <-> $1 LIM...
                                                             ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.

demo=# PREPARE q2(text) AS SELECT id FROM items ORDER BY embedding <-> $1::vector LIMIT 5;
PREPARE

Cause. Your driver bound the query vector as text (common with ORMs and with string-formatted embeddings), and there's no distance operator for vector and text. Fix. Cast the parameter — $1::vector — or register pgvector's type adapter so the driver sends a real vector (register_vector(conn) in pgvector-python, pgvector.registerTypes(client) in pgvector-node). See language bindings.

NaN not allowed in vector#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# SELECT '[1,NaN,3]'::vector;
ERROR:  NaN not allowed in vector
LINE 1: SELECT '[1,NaN,3]'::vector;
               ^

demo=# SELECT '[1,Infinity,3]'::vector;
ERROR:  infinite value not allowed in vector
LINE 1: SELECT '[1,Infinity,3]'::vector;
               ^

pgvector rejects NaN and infinite elements because they make every distance undefined. They usually come from normalising a zero vector (division by zero) or from a failed embedding call that returned garbage. Validate in your pipeline before insert. Zero vectors are legal but cause a quieter version of the same problem — cosine distance to them is NaN:

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# SELECT l2_normalize('[0,0,0]'::vector) AS normalized_zero, '[0,0,0]'::vector <=> '[1,2,3]' AS cosine_to_zero;
 normalized_zero | cosine_to_zero 
-----------------+----------------
 [0,0,0]         |            NaN
(1 row)

Find them with SELECT count(*) FROM items WHERE vector_norm(embedding) = 0; and re-embed or delete those rows.

"70000" is out of range for type halfvec#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# SELECT '[70000]'::halfvec;
ERROR:  "70000" is out of range for type halfvec
LINE 1: SELECT '[70000]'::halfvec;
               ^

Half precision tops out at ±65,504. Normalised embeddings are nowhere near that, so this points to unnormalised features (counts, prices) being stored as vectors. Keep those as vector, or scale them first.

different bit lengths 3 and 4#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# SELECT '101'::bit(3) <~> '1011'::bit(4);
ERROR:  different bit lengths 3 and 4

Hamming and Jaccard distances need equal-length bit strings. With binary_quantize() the length equals the source vector's dimensions, so this again means mixed embedding sizes.

Creating indexes#

column cannot have more than 2000 dimensions for hnsw index#

psqltext-embedding-3-large at full size (3,072 dimensions)
demo=# CREATE TABLE big (id bigserial PRIMARY KEY, embedding vector(3072));
CREATE TABLE

demo=# CREATE INDEX ON big USING hnsw (embedding vector_cosine_ops);
ERROR:  column cannot have more than 2000 dimensions for hnsw index

demo=# CREATE INDEX ON big USING ivfflat (embedding vector_cosine_ops);
ERROR:  column cannot have more than 2000 dimensions for ivfflat index

Cause. A vector index entry must fit on an 8 KB page, which caps vector indexes at 2,000 dimensions for both HNSW and IVFFlat. It's the most common error with OpenAI's text-embedding-3-large (3,072) and other large models.

Fix 1 — index a halfvec cast (up to 4,000 dimensions). Keep the full-precision column; index a half-precision expression:

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# CREATE INDEX ON big USING hnsw ((embedding::halfvec(3072)) halfvec_cosine_ops);
CREATE INDEX

Queries must use the same expression to hit the index: ORDER BY embedding::halfvec(3072) <=> $1::halfvec(3072) LIMIT 10. On our 3,072-dim DBpedia test this index reached recall@10 of 0.937 at the default ef_search of 40 (4.1 ms median).

Fix 2 — shorten the embedding. OpenAI's v3 models accept a dimensions parameter. In our measurements, truncating 3,072-dim vectors to 1,536 kept 89.0% of the exact top-10 neighbours. Full analysis in halfvec & quantization.

Fix 3 — binary quantization with re-ranking (up to 64,000 dimensions). Details in the quantization guide.

column cannot have more than 4000 dimensions for hnsw index#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# CREATE TABLE huge (id bigserial PRIMARY KEY, embedding vector(4096));
CREATE TABLE

demo=# CREATE INDEX ON huge USING hnsw ((embedding::halfvec(4096)) halfvec_cosine_ops);
ERROR:  column cannot have more than 4000 dimensions for hnsw index

The halfvec limit. Above 4,000 dimensions your options are binary quantization (bit indexes go to 64,000), indexing a subvector, or reducing dimensions. Separately, the vector type itself can't exceed 16,000 dimensions:

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# CREATE TABLE toomany (embedding vector(16001));
ERROR:  dimensions for type vector cannot exceed 16000
LINE 1: CREATE TABLE toomany (embedding vector(16001));
                                        ^

column does not have dimensions#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# CREATE TABLE docs (id bigserial PRIMARY KEY, embedding vector);
CREATE TABLE

demo=# CREATE INDEX ON docs USING hnsw (embedding vector_cosine_ops);
ERROR:  column does not have dimensions

Indexes need a fixed size. Either alter the column (ALTER TABLE docs ALTER COLUMN embedding TYPE vector(1536);) or, if the column deliberately holds several sizes, index a cast with a partial-index condition: CREATE INDEX ON docs USING hnsw ((embedding::vector(1536)) vector_cosine_ops) WHERE model_id = 1;

ef_construction must be greater than or equal to 2 * m#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WITH (m = 32, ef_construction = 40);
ERROR:  ef_construction must be greater than or equal to 2 * m

pgvector requires ef_construction ≥ 2 × m. With m = 32, use at least 64. Our build-option measurements show the defaults (m = 16, ef_construction = 64) are a good start for 1,536-dim embeddings.

value 200 out of bounds for option "m"#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# CREATE INDEX ON items USING hnsw (embedding vector_l2_ops) WITH (m = 200);
ERROR:  value 200 out of bounds for option "m"
DETAIL:  Valid values are between "2" and "100".

Allowed ranges: HNSW m 2–100, ef_construction 4–1,000; IVFFlat lists 1–32,768. Values far above the defaults rarely help — see the measured trade-offs in the HNSW guide.

2000 is outside the valid range for parameter "hnsw.ef_search"#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# SET hnsw.ef_search = 2000;
ERROR:  2000 is outside the valid range for parameter "hnsw.ef_search" (1 .. 1000)

hnsw.ef_search accepts 1–1,000. If you need more than 1,000 candidates (for example to re-rank or to survive a selective filter), use iterative index scans instead. By contrast, ivfflat.probes accepts up to 32,768:

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# SET ivfflat.probes = 2000;
SET

demo=# SHOW ivfflat.probes;
 ivfflat.probes 
----------------
 2000
(1 row)

invalid value for parameter "ivfflat.iterative_scan"#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# SET ivfflat.iterative_scan = strict_order;
ERROR:  invalid value for parameter "ivfflat.iterative_scan": "strict_order"
HINT:  Available values: off, relaxed_order.

IVFFlat only supports off and relaxed_order; strict_order exists only for hnsw.iterative_scan. The HINT line lists the valid values.

memory required is 6 MB, maintenance_work_mem is 1 MB#

psqlIVFFlat build with 1,000 lists of 1,536-dim vectors
demo=# CREATE TABLE ivf_mem (id bigserial PRIMARY KEY, embedding vector(1536));
CREATE TABLE

demo=# INSERT INTO ivf_mem (embedding) SELECT (SELECT array_agg(random())::vector(1536) FROM generate_series(1, 1536) WHERE g > 0) FROM generate_series(1, 2000) g;
INSERT 0 2000

demo=# SET maintenance_work_mem = '1MB';
SET

demo=# CREATE INDEX ON ivf_mem USING ivfflat (embedding vector_l2_ops) WITH (lists = 1000);
ERROR:  memory required is 6 MB, maintenance_work_mem is 1 MB

demo=# RESET maintenance_work_mem;
RESET

IVFFlat holds every list centre in memory during the build (lists × dimensions × 4 bytes, plus overhead). Raise maintenance_work_mem for the session — SET maintenance_work_mem = '1GB'; — or use fewer lists.

hnsw graph no longer fits into maintenance_work_mem#

Not an error, but the most expensive notice in pgvector:

outputBuilding HNSW on 100,000 × 1,536-dim vectors with the default 64 MB
NOTICE:  hnsw graph no longer fits into maintenance_work_mem after 9753 tuples
DETAIL:  Building will take significantly more time.
HINT:  Increase maintenance_work_mem to speed up builds.

The build keeps going, but switches from fast in-memory construction to inserting through the buffer cache. In our test the same 100,000-row index took 10.4 min with 64 MB versus 3.6 min with 4 GB — 2.9× slower. Set maintenance_work_mem above your expected index size before building (the storage calculator estimates it), but below the RAM you can spare.

ivfflat index created with little data#

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# CREATE TABLE empty_items (id bigserial PRIMARY KEY, embedding vector(3));
CREATE TABLE

demo=# CREATE INDEX ON empty_items USING ivfflat (embedding vector_l2_ops) WITH (lists = 100);
NOTICE:  ivfflat index created with little data
DETAIL:  This will cause low recall.
HINT:  Drop the index until the table has more data.
CREATE INDEX

IVFFlat learns its list centres from the rows present at build time. Built on an empty table, every later row lands in arbitrary lists and recall collapses. Load your data first, then create the index — or use HNSW, which has no training step.

could not resize shared memory segment … No space left on device#

Docker gives containers a 64 MB /dev/shm by default, and parallel index builds allocate shared memory up to maintenance_work_mem. Start the container with --shm-size at least as large as maintenance_work_mem (e.g. --shm-size=2g, or shm_size: 2g in Compose). The upstream README documents this; our Docker command builder sets both together.

Performance and result problems#

The index isn't used#

Run EXPLAIN. You want Index Scan using … with an Order By line. Here is one HNSW index built with vector_l2_ops, and five queries — only some of them can use it:

psqlOne index, six query shapes (enable_seqscan off to make the planner show its hand)
demo=# CREATE INDEX ON items USING hnsw (embedding vector_l2_ops);
CREATE INDEX

demo=# SET enable_seqscan = off;
SET

demo=# EXPLAIN (COSTS OFF) SELECT id FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
                     QUERY PLAN                      
-----------------------------------------------------
 Limit
   ->  Index Scan using items_embedding_idx on items
         Order By: (embedding <-> '[3,1,2]'::vector)
(3 rows)

demo=# EXPLAIN (COSTS OFF) SELECT id FROM items ORDER BY embedding <=> '[3,1,2]' LIMIT 5;
                      QUERY PLAN                       
-------------------------------------------------------
 Limit
   ->  Sort
         Sort Key: ((embedding <=> '[3,1,2]'::vector))
         ->  Seq Scan on items
               Disabled: true
(5 rows)

demo=# EXPLAIN (COSTS OFF) SELECT id FROM items ORDER BY embedding <-> '[3,1,2]' DESC LIMIT 5;
                         QUERY PLAN                         
------------------------------------------------------------
 Limit
   ->  Sort
         Sort Key: ((embedding <-> '[3,1,2]'::vector)) DESC
         ->  Seq Scan on items
               Disabled: true
(5 rows)

demo=# EXPLAIN (COSTS OFF) SELECT id FROM items ORDER BY embedding <-> '[3,1,2]';
                  QUERY PLAN                   
-----------------------------------------------
 Index Scan using items_embedding_idx on items
   Order By: (embedding <-> '[3,1,2]'::vector)
(2 rows)

demo=# EXPLAIN (COSTS OFF) SELECT id, embedding <-> '[3,1,2]' AS distance FROM items ORDER BY distance LIMIT 5;
                     QUERY PLAN                      
-----------------------------------------------------
 Limit
   ->  Index Scan using items_embedding_idx on items
         Order By: (embedding <-> '[3,1,2]'::vector)
(3 rows)

demo=# EXPLAIN (COSTS OFF) SELECT id FROM items ORDER BY 1 - (embedding <=> '[3,1,2]') DESC LIMIT 5;
                                      QUERY PLAN                                      
--------------------------------------------------------------------------------------
 Limit
   ->  Sort
         Sort Key: (('1'::double precision - (embedding <=> '[3,1,2]'::vector))) DESC
         ->  Seq Scan on items
               Disabled: true
(5 rows)

demo=# RESET enable_seqscan;
RESET

What the plans tell you:

  • The operator must match the operator class. An L2 index (vector_l2_ops) serves only <->; the <=> query fell back to a sort. Create the index with the opclass for the distance you query: vector_cosine_ops for <=>, vector_ip_ops for <#>.
  • Order by the distance ascending. DESC can't use the index, and neither can ORDER BY 1 - (embedding <=> $1) DESC — the "similarity" form many tutorials use. Order by the raw distance and compute similarity in the select list.
  • A select-list alias is fine. ORDER BY distance where distance is the distance expression uses the index.
  • No LIMIT is a trap. The planner will use the index without a LIMIT if forced, but an HNSW scan returns at most ef_search rows (40 by default) unless iterative scans are on. Always add a LIMIT.

Distance thresholds are a special case — a WHERE distance < x filter can't use the index on its own. Order and limit in a subquery, then filter:

psqlpsql · PostgreSQL 18.6 · pgvector 0.8.7
demo=# SET enable_seqscan = off;
SET

demo=# EXPLAIN (COSTS OFF) SELECT id FROM items WHERE embedding <-> '[3,1,2]' < 5;
                              QUERY PLAN                               
-----------------------------------------------------------------------
 Seq Scan on items
   Disabled: true
   Filter: ((embedding <-> '[3,1,2]'::vector) < '5'::double precision)
(3 rows)

demo=# EXPLAIN (COSTS OFF) SELECT id FROM (SELECT id, embedding <-> '[3,1,2]' AS distance FROM items ORDER BY distance LIMIT 5) t WHERE distance < 5;
                        QUERY PLAN                         
-----------------------------------------------------------
 Subquery Scan on t
   Filter: (t.distance < '5'::double precision)
   ->  Limit
         ->  Index Scan using items_embedding_idx on items
               Order By: (embedding <-> '[3,1,2]'::vector)
(5 rows)

demo=# RESET enable_seqscan;
RESET

On a small table the planner may also legitimately prefer a sequential scan — that's a cost decision, not a bug, and it disappears as the table grows.

Fewer rows than the LIMIT#

With a WHERE filter, an approximate index finds ef_search candidates first and Postgres filters them afterwards. If the filter is selective, few candidates survive. We measured it on 100,000 DBpedia embeddings with a filter that matches 1% of rows, forcing the HNSW index (ef_search = 40, LIMIT 10):

SettingAvg rows returnedRecall@10Median latency
hnsw.iterative_scan = off (default)0.390.0392.7 ms
hnsw.iterative_scan = relaxed_order10.000.96737 ms

Fix it with SET hnsw.iterative_scan = relaxed_order; (pgvector 0.8.0+), a partial index for a hot filter value, or a B-tree on the filter column for very selective filters. The full analysis across four selectivities is in the filtering guide.

Results look wrong or miss obvious matches#

Approximate indexes trade recall for speed. With pgvector's defaults on our 100,000 × 1,536 dataset, HNSW found 94.7% of the true top-10 neighbours; IVFFlat with 316 lists and the default probes = 1 found only 55.0%. Raise the search-time knob and re-measure:

sql
SET hnsw.ef_search = 100;   -- HNSW: default 40
SET ivfflat.probes = 16;    -- IVFFlat: default 1 (!)

To measure your own recall, compare the index's answer with an exact scan inside a transaction where index scans are disabled (SET LOCAL enable_indexscan = off;) — the cheatsheet has a ready query.

Index builds take forever#

Our measured build of an HNSW index on 100,000 × 1,536-dim vectors, varying only memory and parallelism:

HNSW build time: memory, parallel workers and load order

Same 100,000 × 1,536-dim vectors, same index (m 16, ef_construction 64). Workers launched were counted from pg_stat_activity.

SetupBuild timeParallel workers
Index first, then load 100K rows13.8 min0 workers (row-by-row inserts)
64 MB maintenance_work_mem (default)10.4 min0 workers launched
256 MB maintenance_work_mem8.3 min0 workers launched
4 GB, max_parallel_maintenance_workers = 33.4 min0 workers launched
4 GB + ALTER TABLE SET (parallel_workers = 1)1.8 min1 worker launched
4 GB + ALTER TABLE SET (parallel_workers = 3)56 s3 workers launched
Measured on PostgreSQL 18.6 + pgvector 0.8.7, 4 vCPU / 15 GB, DBpedia × OpenAI text-embedding-3-large.Method & raw data

Check three things:

  • maintenance_work_mem large enough for the graph (about 6.7 KB per 1,536-dim row), or you'll see the "no longer fits" notice.
  • Parallel workers that actually start. With 1,536-dim vectors the main heap is tiny (the vectors live in TOAST), and below 8 MB of heap — about 160,000 rows — PostgreSQL plans zero workers no matter what max_parallel_maintenance_workers says. We counted: 0 workers and 3.4 min; after ALTER TABLE items SET (parallel_workers = 3);, 3 workers and 56 s. Details.
  • Load first, index second — inserting the same 100,000 rows into an already-indexed table took 13.8 min.

Build-from-source errors#

MessageFix
fatal error: postgres.h: No such file or directoryInstall the server headers: postgresql-server-dev-18 (Debian/Ubuntu) or postgresql18-devel (PGDG RHEL). On macOS check pg_config --includedir-server.
Builds against the wrong Postgresexport PG_CONFIG=/path/to/18/bin/pg_config, make clean, rebuild, and sudo --preserve-env=PG_CONFIG make install.
Illegal instruction at runtimeCompiled with -march=native on a different CPU. Rebuild with make OPTFLAGS="".
warning: no such sysroot directory (macOS)The SDK path recorded when Postgres was built no longer exists. Compare it with pg_config --cppflags and reinstall Postgres.
Windows: postgres.h, C2196, float_to_shortest_decimal_bufn, Access is deniedSee Windows build errors.

Still stuck? Email hello@pgvector.app with the full error and your SELECT version(); — we add new cases to this page. For bugs in pgvector itself, the upstream issue tracker is the right place.

Frequently asked questions

Why does my pgvector query return fewer rows than the LIMIT?

An approximate index scans a fixed-size candidate list (hnsw.ef_search, 40 by default) and Postgres applies your WHERE clause afterwards. In our test with a filter matching 1% of 100,000 rows, a plain HNSW scan returned an average of 0.39 rows for LIMIT 10. Turning on SET hnsw.iterative_scan = relaxed_order; brought it back to 10.0.

Why isn't my HNSW index being used?

The three usual causes: the query's operator doesn't match the index's operator class (an index built with vector_l2_ops can't serve <=>), the query orders by an expression such as 1 - (embedding <=> $1) instead of the distance itself, or there is no LIMIT. Run EXPLAIN and look for Index Scan using ….

How do I index embeddings with more than 2,000 dimensions?

Index a half-precision cast instead: CREATE INDEX ON items USING hnsw ((embedding::halfvec(3072)) halfvec_cosine_ops); and query with ORDER BY embedding::halfvec(3072) <=> $1::halfvec(3072). That works up to 4,000 dimensions; beyond that use binary quantization (up to 64,000 bits) with re-ranking.