Problem connecting n8n to chroma vector store

Describe the problem/error/question

I have an self-hosted version of n8n:2.30.7, and a self-hosted version of chromadb/chroma:1.5.9, on azure.
Both in the same vnet, and working fine alone as they should.
But when I try to use the node “Chroma Vector Store”, it does not load any Chroma Collections, and when try to execute passing the ID, it just returns an error about “CORS” in chroma, but it is allowed to “*”
But when I try to send an HTTP request to the same endpoint, to the heartbeat endpoint for example, it returns a response, and I don’t know what to do anymore

What is the error message (if any)?

And this is my chroma dockerfile and config.yaml

FROM chromadb/chroma:1.5.9

ENV IS_PERSISTENT=TRUE
ENV PERSIST_DIRECTORY=/data
ENV ANONYMIZED_TELEMETRY=FALSE
ENV CHROMA_SERVER_CORS_ALLOW_ORIGINS=["*"]
ENV CHROMA_CORS_ALLOW_ORIGINS=["*"]

COPY config.yaml /config.yaml

EXPOSE 8000
is_persistent: true
persist_path: /data
anonymized_telemetry: false
allow_reset: false
chroma_server_cors_allow_origins: ["*"]
CHROMA_CORS_ALLOW_ORIGINS: ["*"]

Please share your workflow


(Select the nodes on your canvas and use the keyboard shortcuts CMD+C/CTRL+C and CMD+V/CTRL+V to copy and paste the workflow.)

Share the output returned by the last node

NodeOperationError: Error connecting to ChromaDB: Chroma getOrCreateCollection error: Failed to connect to chromadb. Make sure your server is running and try again. If you are running from a browser, make sure that your chromadb instance is configured to allow requests from the current origin using the CHROMA_SERVER_CORS_ALLOW_ORIGINS environment variable. at Object.getVectorStoreClient (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@n8n+n8n-nodes-langchain@file+packages+@n8n+nodes-langchain_2c7f106572ec97ecf6e9416b33a264bd/node_modules/@n8n/n8n-nodes-langchain/nodes/vector_store/VectorStoreChromaDB/VectorStoreChromaDB.node.ts:405:10) at processTicksAndRejections (node:internal/process/task_queues:104:5) at handleLoadOperation (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@n8n+ai-utilities@file+packages+@n8n+ai-utilities_c531a0ff6f04dcb4053a88d226097fe6/node_modules/@n8n/ai-utilities/src/utils/vector-store/createVectorStoreNode/operations/loadOperation.ts:22:22) at ExecuteContext.execute (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/@n8n+ai-utilities@file+packages+@n8n+ai-utilities_c531a0ff6f04dcb4053a88d226097fe6/node_modules/@n8n/ai-utilities/src/utils/vector-store/createVectorStoreNode/createVectorStoreNode.ts:427:19) at WorkflowExecute.executeNode (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/n8n-core@file+packages+core_@opentelemetry+api@1.9.0_@opentelemetry+exporter-trace-otlp_cf5896492347c4895f0373f4acc773d7/node_modules/n8n-core/src/execution-engine/workflow-execute.ts:1080:8) at WorkflowExecute.runNode (/usr/local/lib/node_modules/n8n/node_modules/.pnpm/n8n-core@file+packages+core_@opentelemetry+api@1.9.0_@opentelemetry+exporter-trace-otlp_cf5896492347c4895f0373f4acc773d7/node_modules/n8n-core/src/execution-engine/workflow-execute.ts:1380:11) at /usr/local/lib/node_modules/n8n/node_modules/.pnpm/n8n-core@file+packages+core_@opentelemetry+api@1.9.0_@opentelemetry+exporter-trace-otlp_cf5896492347c4895f0373f4acc773d7/node_modules/n8n-core/src/execution-engine/workflow-execute.ts:1842:27 at /usr/local/lib/node_modules/n8n/node_modules/.pnpm/n8n-core@file+packages+core_@opentelemetry+api@1.9.0_@opentelemetry+exporter-trace-otlp_cf5896492347c4895f0373f4acc773d7/node_modules/n8n-core/src/execution-engine/workflow-execute.ts:2534:11

Information on your n8n setup

  • n8n version: 2.30.7
  • Database (default: SQLite): postgres
  • n8n EXECUTIONS_PROCESS setting (default: own, main):
  • Running n8n via (Docker, npm, n8n cloud, desktop app): Docker
  • Operating system: Linux

Hi @Hugo_Fernandes

Simplify your Dockerfile to use only the correctly formatted ENV var:

FROM chromadb/chroma:1.5.9

ENV IS_PERSISTENT=TRUE
ENV PERSIST_DIRECTORY=/data
ENV ANONYMIZED_TELEMETRY=FALSE
ENV CHROMA_SERVER_CORS_ALLOW_ORIGINS=*

Update config.yaml to remove the CORS keys entirely (let ENV handle it):

is_persistent: true
persist_path: /data
anonymized_telemetry: false
allow_reset: false

Verify the specific origin: If wildcard * still doesn’t work, set the exact origin your browser uses to access n8n:

ENV CHROMA_SERVER_CORS_ALLOW_ORIGINS=https://your-n8n-host.azure.com

Since both services are on the same VNet, the Chroma Vector Store node’s collection-loading requests still go browser → ChromaDB. Make sure your ChromaDB container is accessible from your public browser, not just from within the VNet. If ChromaDB is only VNet-internal (no public endpoint), the UI collection list will always fail to load — even though n8n’s own HTTP Request node (server-side) can reach it fine .

If you want ChromaDB to remain purely internal (no public exposure), a workaround is to type the collection name manually using the “Expression” mode in the Chroma Collection field instead of using the dropdown, which bypasses the browser-side listing call entirely.

Thanks for letting us know about this, We have created CV-34 as the internal dev ticket to look into it.

Thanks for letting us know about this, We have created AI-2664 as the internal dev ticket to look into it.

Simplyfied the dockerfile and config.yaml, and tried the

ENV CHROMA_SERVER_CORS_ALLOW_ORIGINS=*

and

ENV CHROMA_SERVER_CORS_ALLOW_ORIGINS=https://your-n8n-host.azure.com

And it did not work either.

Opened the connection for the web without any restrictions before trying, so this part should be OK now.

At the credentials page, it shows as “Connection tested successfully”, so it should be OK connecting to the chroma instance

But it does not return anything but error yet happen.

Please switch to only this setting first:

CHROMA_CORS_ALLOW_ORIGINS='["https://your-n8n-origin"]'

Restart Chroma fully and run this exact check against your Chroma endpoint:

curl -i https://<your-chroma-host>/api/v2/version \
  -H 'Origin: https://<your-n8n-origin>'

When CORS is configured correctly, the response should include an access-control-allow-origin header matching the origin you sent.

If that header is missing, Chroma or the Azure layer in front of it is still not returning browser-usable CORS headers, even if heartbeat and the n8n credential test succeed. If that header is present and correct, then the problem starts to look more like a bug or compatibility gap in the Chroma node path rather than your network setup

So what is the result?

Hi @Hugo_Fernandes
CORS isn’t in play here. The collection dropdown and the node execution both issue their Chroma requests from the n8n server process, not from your browser, so no CHROMA_*_CORS_ALLOW_ORIGINS value can affect either one. That CORS sentence is boilerplate the chromadb JS client appends to every connection failure, whatever the real cause.
A working heartbeat only proves the host is reachable. Point an HTTP Request node at the endpoint the client actually calls:

https://your-chroma-host/api/v2/tenants/default_tenant/databases/default_database/collections

A 404 or 410 there while the heartbeat returns 200 means the client bundled in 2.30.7 and the 1.5.9 server disagree on the API surface, which is a version mismatch rather than anything configurable on your side. That status code is the useful thing to add here, since this is already with the dev team.

The CORS error you’re seeing is likely caused by how the Chroma client inside n8n connects to your server. Even though you set CORS headers in the environment variables, the Chroma Python client used by n8n’s node makes requests that may not respect those headers correctly when the server is behind a proxy or when using Docker networking. A few things to check: In your config.yaml, the keys `chroma_server_cors_allow_origins` and `CHROMA_CORS_ALLOW_ORIGINS` are not valid Chroma config keys. The correct environment variable is `CHROMA_SERVER_CORS_ALLOW_ORIGINS` (note the underscore after SERVER). Remove those lines from config.yaml and only set the environment variable in your Dockerfile or docker-compose. Make sure you’re using the full URL in the Chroma Vector Store node, including the port (e.g., `http://chroma:8000`). If both containers are on the same Docker network, use the service name instead of localhost. Try adding `CHROMA_SERVER_CORS_ALLOW_ORIGINS=[“”]` as a Docker environment variable at runtime rather than in the Dockerfile, and ensure no quotes are being escaped incorrectly. If the heartbeat endpoint works but the collection listing fails, the issue might be with the specific API path the node uses. Test with a direct HTTP request to `/api/v1/collections` to confirm the server responds. As a workaround, you can use the HTTP Request node to interact with Chroma’s REST API directly instead of the dedicated node, which gives you full control over headers and CORS handling

After changing the ENV variable to accept a list with the azure domains.

Testing in postman itself with the headers, it returns the header correctly, but in n8n chroma node it simply does not load

Even in kudu SSH it does returns

In the HTTP trigger, it actuall returns a 200 status code response, is just in the chroma node that does not work

The v1 endpoints returns

410 - "{\"error\":\"Unimplemented\",\"message\":\"The v1 API is deprecated. Please use /v2 apis\"}"

I would treat it as a node-side issue. You may want to use the HTTP Request node as a temporary workaround.

The 200 on v2 rules the version mismatch out. The node builds its Chroma client from the Base URL’s host, protocol and port only, and when the URL carries no explicit port it substitutes 8000. An https URL on the standard port therefore becomes port 8000 inside the node, while the credential test, Postman and the HTTP Request node all keep using 443. That is why everything except the node succeeds.
Adding :443 will not fix it either, the URL parser drops default ports and it falls back to 8000 again. The Base URL needs a port that survives parsing, so expose Chroma on a non-default port and point the credential at it:

https://your-chroma-host:8443

Worth adding the port detail to CV-34 and AI-2664, since it places the failure in how the client is constructed rather than anywhere in your Chroma config.

So probably is an issue with the node, instead my chroma instance in azure?

I’ll see if I can change the port on azure app services with containers, but I think it only listents to 443 for https and 80 for http

Yes, your Chroma instance is fine, the failure is on the node side.
App Service only accepts inbound traffic on 80 and 443, and WEBSITES_PORT only sets the port inside the container, so no Base URL pointed at that host will carry a port through. Chroma needs to sit somewhere you publish the port yourself. An Azure Container Instance in the same VNet subnet gets a private IP and can publish 8000 directly:

az container create --resource-group <rg> --name chroma --image chromadb/chroma:1.5.9 --vnet <your-vnet> --subnet <your-subnet> --ports 8000

Mount an Azure Files share at /data or the collections go on every restart. Then point the credential Base URL at http://<private-ip>:8000.

Pinecone and Qdrant setup in n8n, if you want a store that works while this is open:
https://axshul.site/n8n/guide/vector-stores-and-rag/

I tried locally criating an tuneling in port 8000, and pointing out to the azure endpoint, with nginx:

server {
    listen 8000;

    location / {
        proxy_pass https://az.azurewebsites.net;
        
        proxy_set_header Host az.azurewebsites.net;
        
        proxy_ssl_server_name on;
        
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

And trying locally to connect

It works, so it really is putting port 8000

Searching in github this specific node, has code:


The new URL removes if ports :443 or :80 is passed, and puts the port 8000

The nginx tunnel only needs to move off your machine to become the permanent fix. Run it as a container on the same Docker network as n8n with the config you already have, then point the credential Base URL at it:

http://chroma-proxy:8000

If n8n sits on App Service too, run it as a sidecar in the same app and use http://localhost:8000. Plain http keeps ssl off on the client and 8000 survives the URL parse, so the node reaches a real listener while Chroma stays on 443 behind App Service, with nothing changed on the Chroma side.

Thanks for the help to discover what was causing the trouble in this pipeline!

I had something similar before and it looked like a CORS issue, but it was actually a connection/config problem. If the HTTP Request node can reach the same Chroma endpoint, I would also check whether the Chroma Vector Store node is using the exact same base URL (including http/https and port). Also make sure n8n can access the endpoint from inside the container, not only from your browser. It may also be worth checking the Chroma server logs while the node is trying to connect, as they sometimes show a more useful error than the n8n message. Hope you find the cause.