LangChain Chroma Get Embeddings: Why They Show None
To langchain chroma get embeddings, call vectorstore.get(include=['embeddings','documents','metadatas']). Chroma omits vectors by default, so 'embeddings: None' is expected behaviour, not a bug, and the vectors are stored.
- Chroma's get() returns only ids, metadatas and documents unless you ask for embeddings through the include argument.
- vectorstore.get(include=['embeddings']) works in LangChain, and collection.get(include=['embeddings']) works in the native client.
- Newer Chroma versions return NumPy arrays, so test with 'is not None' or len(), never 'if embeddings:'.
- Verify storage with collection.count(), len(vector) against the model dimension, and a comparison to embed_query output.
- Chroma, Pinecone, Qdrant and Weaviate return vectors through a read-time flag or call, while FAISS keeps them in the index and reads them back with reconstruct(), which is lossy or unsupported on compressed indexes such as IVF-PQ.
Why does Chroma show embeddings as None?
If you tried to langchain chroma get embeddings and saw 'embeddings: None', nothing is broken. Chroma leaves vectors out of the response unless you ask for them.
Vectors are large. A single 1536-dimension float vector is about 6 KB, so returning them for every get() would make routine inspection slow and heavy. Chroma therefore returns only ids, metadatas and documents unless you opt in.
That means a result like {'ids': [...], 'embeddings': None, 'documents': [...]} is normal. The vectors exist in the index; the response simply left them out.
If include is set and you still see None or nothing, the table below lists the usual causes.
| Symptom | Likely cause | Fix |
|---|---|---|
| embeddings is None | include was not passed | Add include=['embeddings'] |
| Empty ids list | Wrong persist_directory or collection_name | Point at the folder and collection you wrote to |
| Vector length is 384, not 1536 | Chroma's default model was used | Pass the same embedding function you indexed with |
| ValueError: truth value of an array is ambiguous | Embeddings are a NumPy array | Use 'is not None' or len() |
| Count is lower than expected | Documents were not split or the add call failed | Compare count() with the number of chunks |
How do I get embeddings from a LangChain Chroma vector store?
Pass the include argument to get(). It accepts 'embeddings', 'documents', 'metadatas' (and 'uris' or 'data' in some versions). ids are always returned.
The same call accepts ids=[...] to fetch specific records, where={...} to filter on metadata, and limit/offset to page through a large collection.
The example below uses the langchain_chroma package, which is the current home of the integration. Older langchain_community imports still work in some versions but are deprecated.
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
emb = OpenAIEmbeddings(model="text-embedding-3-small")
docs = [Document(page_content="Cats purr.", metadata={"src": "a"}),
Document(page_content="Dogs bark.", metadata={"src": "b"})]
vs = Chroma.from_documents(docs, emb, persist_directory="./db")
data = vs.get(include=["embeddings", "documents", "metadatas"])
vec = data["embeddings"][0]
print(vec[:5]) # first five numbers
print(len(vec)) # 1536
# filters
vs.get(ids=[data["ids"][0]], include=["embeddings"])
vs.get(where={"src": "b"}, include=["embeddings"])How do I use the native Chroma client and peek()?
Outside LangChain, call the collection directly. peek(limit=10) is a shortcut that returns the first records and, unlike get(), includes embeddings.
Recent Chroma versions return embeddings as NumPy arrays, not Python lists. That changes how you test them: an array in an 'if' statement raises an error, so compare against None and check the length instead.
import chromadb
client = chromadb.PersistentClient(path="./db")
col = client.get_collection("langchain") # LangChain's default name
res = col.get(include=["embeddings", "documents"], limit=3)
print(col.peek(limit=2)["embeddings"])
emb = res["embeddings"]
# WRONG: if emb: -> ValueError: truth value of an array is ambiguous
if emb is not None and len(emb) > 0:
print(emb[0].shape)Can I reach the collection behind a LangChain Chroma object?
Yes: vectorstore._collection is the underlying Chroma collection, so vectorstore._collection.get(include=['embeddings']) and .count() work.
The leading underscore marks it as private. Its name or behaviour can change between LangChain releases, so prefer vectorstore.get() in application code and keep _collection for debugging scripts.
A practical rule: use the public get() in anything that ships, and use _collection only in a notebook where a breaking change costs you a minute, not an outage.
How do I verify the vectors are correct?
Run a short checklist. Each check catches a different failure.
Dimensions by model: text-embedding-ada-002 and text-embedding-3-small give 1536, text-embedding-3-large gives 3072, and all-MiniLM-L6-v2 gives 384.
- Count: vs._collection.count() should equal the number of chunks you added, not the number of source files.
- Dimension: len(vector) must equal the model's dimension. A 384 result when you expected 1536 means Chroma's default model was used because the embedding function was not passed.
- Empty or duplicate vectors: check for all-zero rows or repeated rows with NumPy, which signals empty text or a failed embedding call.
- Match: embed the same text yourself and compare it with the stored vector.
import numpy as np
q = emb.embed_query("Cats purr.") # one text
m = emb.embed_documents(["Cats purr."]) # list of texts
stored = vs.get(where={"src": "a"}, include=["embeddings"])["embeddings"][0]
print(len(q), np.allclose(q, stored, atol=1e-5))How do I get vectors from FAISS, Pinecone, Qdrant and Weaviate?
Chroma, Pinecone, Qdrant and Weaviate use a read-time flag or call to decide whether vectors come back. FAISS works differently: it has no include-style flag, because the vectors live in the index itself and are read back with reconstruct() or reconstruct_n().
In FAISS, the index stores vectors by integer position, and index_to_docstore_id maps each position to a document id. reconstruct() works for flat indexes such as IndexFlatL2, which keep the raw vectors. It is lossy or unsupported for compressed index types such as IVF-PQ, where vectors are stored as quantized codes (and IVF indexes may also need a direct map set up first).
Qdrant and Weaviate follow the Chroma idea most closely: a flag on the read call. Pinecone returns vectors from fetch, but not from query unless you set include_values=True.
| Store | Call to get vectors | Notes |
|---|---|---|
| Chroma | vs.get(include=['embeddings']) | peek() also includes them |
| FAISS | vs.index.reconstruct(i) or reconstruct_n(0, n) | Map i with vs.index_to_docstore_id[i]; exact for flat indexes, lossy or unsupported for IVF-PQ |
| Pinecone | index.fetch(ids=[...]) | Vectors are under each record's values |
| Qdrant | retrieve or scroll with with_vectors=True | Default is False |
| Weaviate | include_vector (for example include_vector=True in a fetch) | Exact syntax depends on client version |
What do similarity search scores mean, and what can I do with the vectors?
similarity_search_with_score returns documents and a score, not the vectors. With Chroma's default L2 distance the score is a distance, so lower means closer. Cosine or inner-product collections use different scales, so check the configured space before comparing numbers.
If you already hold a vector, use similarity_search_by_vector(vec, k=4) or max_marginal_relevance_search_by_vector(vec) to skip re-embedding. This is also how you search with a vector you read from the store.
You can also export to pandas to audit data, then project to 2D with PCA or UMAP to see clusters and outliers. Chunks that sit far from everything else are often boilerplate, empty pages or badly parsed PDFs.
Persistence note: persist_directory holds chroma.sqlite3 and a UUID-named folder of HNSW index binaries. These are not human-readable, so inspect through the API. In Chroma 0.4+ writes persist automatically and no persist() call is needed.
import numpy as np
import pandas as pd
from sklearn.decomposition import PCA
d = vs.get(include=["embeddings", "documents"])
df = pd.DataFrame({"id": d["ids"], "doc": d["documents"],
"vec": list(d["embeddings"])})
xy = PCA(n_components=2).fit_transform(np.vstack(df["vec"]))
print(df.head(), xy[:3])Common questions
Why is langchain chroma embeddings None even with include?
Check that you passed include to the right object and that the collection is not empty. Also confirm you are not reading a different persist_directory or collection_name from the one you wrote to.
Does get() return embeddings as lists or arrays?
Newer Chroma versions return NumPy arrays; older ones returned lists of floats. Use .tolist() if you need JSON-serializable output.
How can I see the vector for a piece of text without querying the database?
Call embedding_function.embed_query('text') for one string or embed_documents([...]) for several. This calls the model directly and shows the same vector Chroma would store.
Why do I get a dimension mismatch error when querying?
The query vector has a different length from the stored vectors, usually because a different embedding model was used at query time. Re-create the store with one model, or load it with the model that built it.
Do I need to call persist() in Chroma?
Not in Chroma 0.4 and later, where data written to a persist_directory is saved automatically. Older code that calls persist() may fail on newer LangChain wrappers.