ChromaDB InvalidDimensionException 512 vs 768 (2026)

The chromadb.errors.InvalidDimensionException: Dimensionality of (512) does not match index dimensionality (768) is the number one ChromaDB error in 2026 RAG apps. The root cause is almost always a mismatched embedding function between when you created the collection and when you query it. Here is what happens, how to fix it, and how to prevent it in production.

Why the InvalidDimensionException happens

Every ChromaDB collection is created with a fixed vector dimension. That dimension is determined by the embedding function you use when calling create_collection(). The default sentence-transformer produces 384-dimensional vectors. OpenAI text-embedding-3-small produces 1536. Anthropic’s Voyage models produce 1024 or 1536 depending on the model. If you later query the collection with a different embedding function that produces vectors of a different dimension, ChromaDB rejects them.

The common scenario: you built the collection with OpenAI embeddings during development, then swapped to sentence-transformers to save cost, without rebuilding the index.

Fix 1: use the same embedding function everywhere

import chromadb
from chromadb.utils.embedding_functions import OpenAIEmbeddingFunction
import os

client = chromadb.PersistentClient(path="./chroma_data")

# ONE embedding function used at both create AND query time
openai_ef = OpenAIEmbeddingFunction(
    api_key=os.environ["OPENAI_API_KEY"],
    model_name="text-embedding-3-small",   # 1536 dims
)

# Create (or reuse) collection with this specific EF
collection = client.get_or_create_collection(
    name="papers",
    embedding_function=openai_ef,
)

# Add documents (EF applied automatically)
collection.add(
    documents=["Retrieval-augmented generation summary"],
    ids=["doc_1"],
)

# Query with the SAME EF (no exception)
results = collection.query(
    query_texts=["What is RAG?"],
    n_results=3,
)
print(results)

Fix 2: rebuild the collection when you switch embedding models

import chromadb
from chromadb.utils.embedding_functions import (
    OpenAIEmbeddingFunction,
    SentenceTransformerEmbeddingFunction,
)

client = chromadb.PersistentClient(path="./chroma_data")

# Step 1: delete the old (wrong-dimension) collection
try:
    client.delete_collection(name="papers")
except Exception:
    pass   # not there yet, safe to skip

# Step 2: recreate with the new EF
new_ef = SentenceTransformerEmbeddingFunction(
    model_name="all-MiniLM-L6-v2"   # 384 dims
)
collection = client.create_collection(
    name="papers",
    embedding_function=new_ef,
)

# Step 3: re-ingest all documents
for doc, doc_id in load_documents_from_source():
    collection.add(documents=[doc], ids=[doc_id])

Fix 3: use different collection names for different EFs

If you need to A/B test embedding models, keep them in separate collections instead of trying to swap in-place.

import chromadb
from chromadb.utils.embedding_functions import (
    OpenAIEmbeddingFunction,
    SentenceTransformerEmbeddingFunction,
)

client = chromadb.PersistentClient(path="./chroma_data")

# Two separate collections, one per embedding model
openai_col = client.get_or_create_collection(
    name="papers_openai_1536",
    embedding_function=OpenAIEmbeddingFunction(
        api_key="...",
        model_name="text-embedding-3-small",
    ),
)

st_col = client.get_or_create_collection(
    name="papers_st_384",
    embedding_function=SentenceTransformerEmbeddingFunction(
        model_name="all-MiniLM-L6-v2",
    ),
)

# Now compare quality across the two without dimension conflict

Fix 4: enforce the EF via a factory function

import chromadb
from chromadb.utils.embedding_functions import OpenAIEmbeddingFunction
import os

def get_embedding_function():
    """Single source of truth for the embedding function."""
    return OpenAIEmbeddingFunction(
        api_key=os.environ["OPENAI_API_KEY"],
        model_name="text-embedding-3-small",
    )

def get_collection(client, name: str):
    """Always uses the shared EF. Impossible to pass the wrong one."""
    return client.get_or_create_collection(
        name=name,
        embedding_function=get_embedding_function(),
    )

client = chromadb.PersistentClient(path="./chroma_data")
collection = get_collection(client, "papers")

Debugging checklist

  • Print the current collection’s expected dimension from its metadata: collection.metadata.
  • Print the actual vector dimension your embedding function produces: len(ef(["test"])[0]).
  • Search your codebase for every place a collection is created or queried. Confirm they all import from the same EF factory.
  • If you use LangChain’s Chroma wrapper, verify you pass the same embedding_function argument to both the ingest step and the retriever creation step.

Real-world example: RAG pipeline that survives EF changes

import chromadb
import os
from chromadb.utils.embedding_functions import OpenAIEmbeddingFunction

EF_MODEL = os.environ.get("EMBEDDING_MODEL", "text-embedding-3-small")
DIM_BY_MODEL = {
    "text-embedding-3-small": 1536,
    "text-embedding-3-large": 3072,
    "all-MiniLM-L6-v2": 384,
}
COLLECTION_NAME = f"papers_{EF_MODEL.replace('-', '_')}_{DIM_BY_MODEL[EF_MODEL]}"

client = chromadb.PersistentClient(path="./chroma_data")

ef = OpenAIEmbeddingFunction(
    api_key=os.environ["OPENAI_API_KEY"],
    model_name=EF_MODEL,
)

# Collection name includes the model + dimension, so swapping the env var
# creates a fresh isolated collection rather than a broken one
collection = client.get_or_create_collection(
    name=COLLECTION_NAME,
    embedding_function=ef,
)

# Safe to switch EMBEDDING_MODEL between deploys without dimension conflicts
collection.add(
    documents=["Chunk of source text 1", "Chunk of source text 2"],
    ids=["c1", "c2"],
)

results = collection.query(query_texts=["source text 1 semantic match"], n_results=2)
print(results["documents"])

Common mistakes with ChromaDB dimensions

  • Creating a collection without specifying the EF. Chroma silently uses the default sentence-transformer (384). Query time with a different EF then explodes.
  • Passing embeddings directly to add() in one place and letting the EF compute them elsewhere. Mixed approaches are fine but only if the vector dimensions match.
  • Assuming get_collection() restores the original EF. It does not. You must pass the EF again every time you open the collection.
  • Deleting only the client cache without deleting the collection. The persistent store keeps the old dimension. Full delete_collection() is required to reset.

Debugging checklist for the SDK/library error

Before diving into fixes, run through this diagnostic checklist. Nine times out of ten the answer surfaces here.

  1. Read the full traceback, not just the error message. The stack trace shows exactly which line and which call chain triggered the error. The last line names the immediate cause; earlier lines show how you got there.
  2. Add print or debug statements just before the failing line. Print the variable, its type, and its value. Nine out of ten error surprises come from the value being different from what you assumed.
  3. Check Python version compatibility. Errors sometimes result from APIs that changed between versions. Run your interpreter version check and compare against the library documentation for that version.
  4. Isolate the failing call in a minimal reproducer. Copy the failing line into a small standalone script with hardcoded inputs. If it fails there too, the bug is in your code. If not, something in your surrounding context is contributing.
  5. Search the exact error message. Include the class name and the specific text in your search. Chances are someone else hit the same issue and the fix is documented on Stack Overflow or the library’s GitHub issues.

Common causes for the SDK/library error

Most instances of this error trace back to one of these root causes:

  • Uninitialized or missing input. A variable was not populated before use, or the input source (file, API response, database row) did not contain the expected key or value.
  • Type mismatch. The code expected a specific type (dict, list, string) but received something different. Python’s dynamic typing means this often surfaces at runtime, not at compile time.
  • Version drift. The library API changed and your code assumes the old signature. Check the library’s changelog for breaking changes since the version you last used.
  • Race condition or ordering issue. Async or concurrent code sometimes tries to access data before it is ready. Add awaits, locks, or explicit ordering to fix.
  • Copy-paste from stale tutorial. Older tutorials may use APIs that no longer exist. Always check the official docs for the current version.

Testing and prevention

Preventing this class of error from recurring is more valuable than fixing it once. Build these habits into your workflow:

  • Write tests that trigger the error path. If your test suite hits the error scenario, catch and assert it. A well-written test prevents the same bug from returning.
  • Validate inputs at API boundaries. When data enters your code from external sources (HTTP requests, file uploads, database queries), validate structure and types immediately.
  • Use type hints and static analysis. Tools like mypy for Python or TypeScript for JavaScript catch many type mismatches before you run the code.
  • Log important state. Structured logging with context helps you debug production issues faster. Include enough context to reconstruct what happened.
  • Read the library changelog. Before upgrading a dependency, skim the changelog for breaking changes. Two minutes of reading saves an hour of debugging.

When to ask for help

Some errors are worth solving yourself for the learning. Others are worth asking about early. Ask for help when: the error blocks a customer-facing feature, you have spent an hour without progress, the error involves security or data integrity, or you are unsure whether your fix will introduce new bugs. Post to Stack Overflow with a minimal reproducer, or ask a senior developer on your team. Time boxes are your friend.

Frequently Asked Questions

Can I resize a Chroma collection’s dimension in place?

No. Collection dimension is fixed at creation. You must delete and recreate the collection, then re-ingest documents with the new embedding function.

Does get_or_create_collection() preserve the original EF?

No. You must pass the embedding_function argument every time. If you omit it, Chroma falls back to the default and dimension conflicts follow.

What is the default embedding function dimension?

384 (from all-MiniLM-L6-v2 sentence-transformer). If you did not pass an EF at creation, that is the collection’s dimension.

Can I pass raw vectors instead of using an EF?

Yes. Pass embeddings=[[...]] directly to add() and query() instead of documents. Just ensure the vector length matches the collection’s expected dimension.

Does this happen with Pinecone and Qdrant too?

Yes. Every vector DB pins dimension at index creation. Pinecone silently rejects, Qdrant swallows if wait=False. ChromaDB raises InvalidDimensionException which is the loudest and best behavior for debugging.

Adrian Mercurio

Full-Stack Developer at PIES IT Solution

Specializes in building complete capstone projects with full documentation. Strong background in PHP/MySQL development and database design. Has personally built and tested over 30 capstone-ready projects with ER diagrams, DFDs, and chapter-by-chapter thesis documentation.

Expertise: PHP · Laravel · Database Design · Capstone Projects · C# · C · C++ · Python · AI Projects  · View all posts by Adrian Mercurio →

Leave a Comment