Problem – ChromaDB Connection Timeout During RAG Inference Serving
When deploying a Retrieval‑Augmented Generation (RAG) service, the inference container repeatedly fails to retrieve documents from the ChromaDB vector store. The request handler logs a ConnectionTimeoutError after the client’s requests call exceeds the configured 5 second deadline, and the service returns a 504 response to the downstream API consumer.
Typical symptom stack trace:
2026-10-30 14:22:07,842 ERROR inference_worker.py:112
Traceback (most recent call last):
File "/app/inference_worker.py", line 98, in retrieve_documents
results = chroma_client.query(
File "/usr/local/lib/python3.11/site-packages/chromadb/api/client.py", line 210, in query
resp = self._http_client.post(url, json=payload, timeout=self.timeout)
File "/usr/local/lib/python3.11/site-packages/httpx/_client.py", line 1234, in post
response = self.request("POST", url, **kwargs)
File "/usr/local/lib/python3.11/site-packages/httpx/_client.py", line 1192, in request
raise ConnectTimeout("Connection timed out.")
httpx.ConnectTimeout: Connection timed out.
In addition, occasional log entries show authentication failures from the ChromaDB server:
2026-10-30 14:22:09,113 WARN chroma_server.py:45
Authentication failed for token: ****
The failure prevents the RAG pipeline from augmenting LLM responses with relevant context, effectively breaking the inference service.
Root Cause – Mismatched Network & Authentication Configuration
Investigation revealed two intertwined root causes:
- Network reachability issue: The inference container runs in a Kubernetes pod behind a
NetworkPolicythat only permits egress to ports 80/443. ChromaDB is exposed on port8000(HTTP) and8443(HTTPS). The policy blocked traffic, causing the client’s TCP SYN to be dropped, which the HTTP client interprets as a timeout. - Token‑based authentication mismatch: The ChromaDB server was upgraded to
v0.4.0, which introduced mandatory JWT validation. The inference service still used the legacy static API key stored in a ConfigMap. The server rejected the key, emitting the “Authentication failed” warning. Because the request never completed the TLS handshake, the client timed out before receiving the 401 response.
Both problems manifested as a timeout because the client’s retry logic masks the underlying 401 error when the TCP connection cannot be established.
Debug – Systematic Investigation Steps
1. Verify pod‑to‑service connectivity
# From inside the inference pod
kubectl exec -it $(kubectl get pod -l app=inference -o jsonpath='{.items[0].metadata.name}') -- /bin/sh
# Test TCP connectivity to ChromaDB service
nc -zvw5 chromadb-service.default.svc.cluster.local 8000
# Expected output:
# Connection to chromadb-service.default.svc.cluster.local 8000 port [tcp/http] succeeded!
If the command hangs or reports “Connection timed out”, a network policy or Service/Endpoint misconfiguration is present.
2. Inspect NetworkPolicy rules
kubectl get networkpolicy -n default -o yaml | grep -A5 -B5 "podSelector:
matchLabels:
app: inference"
Confirm that egress rules include the ChromaDB service ports.
3. Capture traffic with tcpdump
kubectl exec -it $(kubectl get pod -l app=inference -o jsonpath='{.items[0].metadata.name}') -- \
tcpdump -i any -nn -s 0 port 8000 or port 8443 -c 5 -w /tmp/capture.pcap
# Retrieve the pcap for analysis
kubectl cp $(kubectl get pod -l app=inference -o jsonpath='{.items[0].metadata.name}'):/tmp/capture.pcap ./capture.pcap
Examine the pcap in Wireshark; a missing SYN‑ACK indicates egress blockage.
4. Validate authentication token
# Decode the JWT used by the inference service (if any)
jwt decode $(cat /etc/secrets/chroma_jwt) --no-verify
Check the exp claim and the iss field against the server’s expected issuer.
5. Review ChromaDB server logs
kubectl logs -l app=chromadb -c server --tail=100
2026-10-30 14:20:55,012 INFO server.py:112 Starting ChromaDB on 0.0.0.0:8000
2026-10-30 14:22:09,113 WARN auth.py:45 Authentication failed for token: ****
2026-10-30 14:22:09,115 INFO server.py:210 Request from 10.2.3.45:54321 rejected (401)
Solution – Align Network Policy and Authentication Mechanisms
1. Update NetworkPolicy to allow ChromaDB egress
Before:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: inference-egress
spec:
podSelector:
matchLabels:
app: inference
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
After: add the ChromaDB ports.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: inference-egress
spec:
podSelector:
matchLabels:
app: inference
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
- protocol: TCP
port: 8000 # HTTP endpoint of ChromaDB
- protocol: TCP
port: 8443 # HTTPS endpoint of ChromaDB
Apply the updated policy:
kubectl apply -f inference-egress.yaml
2. Switch to JWT authentication compatible with ChromaDB v0.4.0
Generate a new token using the server’s secret key (or configure the server to accept the legacy API key).
Before (legacy config):
# config.yaml
chroma:
api_key: "legacy-static-key"
endpoint: "http://chromadb-service:8000"
After (JWT config):
# config.yaml
chroma:
jwt_token: "{{ env.CHROMA_JWT }}" # injected via secret
endpoint: "https://chromadb-service:8443"
verify_ssl: true
Update the Kubernetes secret:
# Generate JWT (example using python-jose)
python - <<'PY'
import jwt, datetime, os
payload = {
"sub": "inference-service",
"iss": "my-org",
"exp": datetime.datetime.utcnow() + datetime.timedelta(hours=2)
}
secret = os.getenv("CHROMA_JWT_SECRET")
token = jwt.encode(payload, secret, algorithm="HS256")
print(token)
PY
# Store token in a secret
kubectl create secret generic chroma-auth \
--from-literal=CHROMA_JWT=$(cat token.txt) \
--dry-run=client -o yaml | kubectl apply -f -
Mount the secret as an environment variable in the inference deployment:
env:
- name: CHROMA_JWT
valueFrom:
secretKeyRef:
name: chroma-auth
key: CHROMA_JWT
3. Adjust client timeout (optional)
If network latency is expected to be higher, increase the HTTP client timeout to avoid premature failures.
# inference_worker.py
import httpx
chroma_client = httpx.Client(
base_url=os.getenv("CHROMA_ENDPOINT"),
timeout=30.0, # increased from default 5s
headers={"Authorization": f"Bearer {os.getenv('CHROMA_JWT')}"}
)
Verify – Confirm the Fix Works in Production
- Redeploy the inference service and the updated NetworkPolicy.
- Run a health‑check endpoint that forces a ChromaDB query:
curl -s http://inference-service.default.svc.cluster.local/healthz?test=chroma | jq .
{
"chroma_connection": "ok",
"retrieved_documents": 3
}
Expected log entry:
2026-10-30 14:45:12,021 INFO inference_worker.py:112 Document retrieval succeeded (3 hits)
Run a load test (e.g., hey or locust) and verify that latency remains < 200 ms for the retrieval step.
Prevent – Operational Guardrails and Monitoring
- NetworkPolicy audit: Include ChromaDB ports in the egress whitelist for any pod that accesses the vector store. Use a CI lint rule that validates
NetworkPolicyobjects against a whitelist of required service ports. - Authentication drift detection: Deploy a periodic job that attempts a lightweight
pingquery to ChromaDB using the current token. Alert on 401/403 responses. - Metrics: Export
httpx.request.durationandhttpx.request.errorsto Prometheus. Create alerts for error rate > 1% or latency > 5 s. - Secret rotation policy: Rotate JWTs every 24 h and enforce a
expclaim no longer than 2 h. Automate rotation with a Kubernetes CronJob. - Version pinning: Keep the ChromaDB client library version aligned with the server major version. Use
requirements.txtwith an explicit version range (e.g.,chromadb>=0.4.0,<0.5.0).
FAQ – Common Follow‑Up Questions
- Why does the inference service work in dev but time out in prod?
Dev clusters often have permissive egress rules and run ChromaDB on the default HTTP port (80/443). Production enforces strictNetworkPolicyand the server was upgraded to require JWTs, causing both connectivity and auth failures. - Can I keep using the legacy API key?
Only if you downgrade the ChromaDB server to a version prior to the JWT enforcement (v0.3.x) or explicitly disable therequire_authflag in the server config. Maintaining the legacy key is discouraged because it bypasses token expiration. - What if I need to run ChromaDB behind a load balancer?
Expose the service via aServiceof typeLoadBalancerorIngressthat terminates TLS, then configure the inference client to use the external URL and setverify_ssl=Falseonly for internal testing. Ensure the load balancer forwards theAuthorizationheader. - How do I debug intermittent timeouts that appear only under load?
Collecttcpdumptraces during peak traffic, look for SYN retransmissions or TCP window stalls. Correlate with pod CPU/Memory metrics; a saturated CPU can delay the client’s request processing, causing the server to close idle connections. - Is there a way to test JWT validity without hitting the full query endpoint?
ChromaDB exposes a/auth/validateendpoint. A simplecurl -H "Authorization: Bearer $TOKEN" https://chromadb:8443/auth/validatereturns 200 if the token is accepted, 401 otherwise.
Related Topic Hub: Vector Databases Troubleshooting Hub