Arize Phoenix Troubleshooting Guide: Fix Missing OTLP Traces, Database Errors, and High Memory Usage
If your traces disappear, your database throws errors, or your container’s memory keeps climbing, this Arize Phoenix troubleshooting guide walks you through every fix in a clear order, from the app code to the database to the server itself.
Table of Contents
What Causes Most Arize Phoenix Troubleshooting Cases
Most Arize Phoenix troubleshooting cases depend on:
- Bad instrumentation
- Wrong OTLP endpoints
- Protocol or port mismatches
- Storage problems
- Resource limits on the host
Working through them in that order saves time, because a network issue can look exactly like a database issue if you check things out of sequence.
This guide assumes you already have Phoenix running from the self-host Arize Phoenix with the Docker setup guide, and it focuses only on fixing problems after deployment as part of ongoing Arize Phoenix troubleshooting.
Step 1. Confirm Your App Is Sending Traces to Phoenix
The first step is to verify that the instrumented app produces traces. Add a console exporter next to your real exporter so traces print to your terminal even if the network call to Phoenix fails:
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor
from phoenix.otel import register
tracer_provider = register(project_name="default", auto_instrument=True)
tracer_provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
Run your app once. If traces print in the terminal, your instrumentation is fine, and this Arize Phoenix troubleshooting session moves to the network layer.
If nothing prints, the instrumentor is not wrapping your library calls, and you should check that auto_instrument=True is set or that you called the instrumentor for that specific library before making any request.
Step 2. Send a Manual Test Trace to Phoenix
A manual test trace removes your whole application from the equation, which is the fastest way to isolate the problem in any Arize Phoenix troubleshooting workflow.
Use curl to push a minimal trace directly to the collector:
curl -X POST http://<phoenix-host>:6006/v1/traces \
-H "Content-Type: application/x-protobuf" \
--data-binary @test_span.pb
If Phoenix accepts this and the trace shows up in the UI within a few seconds, the collector and storage layers are healthy, and the issue sits in your app’s exporter configuration.
If it fails, move straight to endpoint and port checks below.
Step 3. Validate Phoenix’s OTLP Endpoint and Ports
Wrong endpoints are the most common reason people start an Arize Phoenix troubleshooting search.
Phoenix exposes three separate listeners, and mixing them up causes silent trace loss:
| Port | Protocol | Path | Purpose |
|---|---|---|---|
| 6006 | HTTP | / | Web UI |
| 6006 | HTTP | /v1/traces | OTLP over HTTP (Protobuf) |
| 4317 | gRPC | n/a | OTLP over gRPC |
Set the collector endpoint yourself instead of using the default:
export PHOENIX_COLLECTOR_ENDPOINT="http://<phoenix-host>:6006"
If your SDK exporter is configured for gRPC, point it at port 4317 with no path appended, since gRPC does not use the /v1/traces path that HTTP uses.
Pointing an HTTP exporter at 4317 or a gRPC exporter at 6006 will both fail, and this mismatch is the second most frequent cause behind slow Arize Phoenix troubleshooting fixes.
Step 4. Fix Phoenix Exporter Retry and Connection Errors
If logs show “socket hang up” or repeated connection resets, switch from the HTTP exporter to the gRPC exporter, which handles long-lived connections more reliably for high-volume trace traffic:
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor
exporter = OTLPSpanExporter(endpoint="http://<phoenix-host>:4317", insecure=True)
tracer_provider.add_span_processor(BatchSpanProcessor(exporter))
Also, switching to BatchSpanProcessor reduces the number of network round trips, which cuts down on exporter retries and timeout errors that show up as gaps in the trace timeline.
If retries keep happening after this change, a firewall is probably blocking the gRPC port. The problem is usually not Phoenix itself.
Step 5. Handle Phoenix Parsing Errors and Large Attributes
Big prompts, embeddings, or base64 images can be too large for Phoenix to handle. This causes NOT_PARSABLE errors or cuts off traces. Shrink large data before sending it, or save just a short hash and store the full content somewhere else.
span.set_attribute("llm.input", input_text[:4000])
Also, check that you’re using Phoenix version 0.17.4 or later. Older versions cut off OpenAI responses too early, which broke the JSON and caused parsing errors. This version issue comes up a lot in Arize Phoenix troubleshooting. Updating the container image fixes most of these oversized-attribute problems.
Step 6. Fix Failed Migrations in Phoenix’s Database
Persistence failures usually come from a dirty migration state or a PostgreSQL version mismatch, and both are common triggers for Arize Phoenix troubleshooting when moving from SQLite to Postgres.
Use your PostgreSQL image version in docker-compose.yml instead of using latest:
services:
db:
image: postgres:16
restart: always
environment:
- POSTGRES_USER=phoenix
- POSTGRES_PASSWORD=phoenix
- POSTGRES_DB=phoenix
volumes:
- phoenix_db_data:/var/lib/postgresql/data
Point Phoenix at that database using a single connection string:
export PHOENIX_SQL_DATABASE_URL="postgresql://phoenix:phoenix@db:5432/phoenix"
If the container logs show “database may be in a dirty state,” run the Alembic CLI from inside the Phoenix source to reset the migration marker:
alembic stamp head
Then restart the container.
If the schema is badly damaged, the quickest fix is usually to point Phoenix at a fresh, empty database instead of trying to repair the old one. Traces don’t need to last long anyway, so starting clean is often easier.
Step 7. Clear Phoenix Database Lock Errors
Database locks happen when more than one Phoenix replica tries to write to the same SQLite file, since SQLite only allows one writer at a time. Never run more than one Phoenix replica with SQLite. Switch to PostgreSQL instead, since it allows multiple writers and avoids this whole problem:
export PHOENIX_SQL_DATABASE_URL="postgresql://user:password@host:5432/phoenix"
If locks persist even on Postgres, check for long-running queries holding row locks with SELECT * FROM pg_stat_activity WHERE state = 'active'; and terminate stuck sessions with pg_terminate_backend(pid). This step closes most database-related Arize Phoenix troubleshooting cases.
Step 8. Control Phoenix’s Data Retention Growth
If you don’t limit how many traces you keep, disk space and slow queries will slowly build up as the traces table grows.
Set an automatic retention window instead of deleting data manually:
export PHOENIX_DEFAULT_RETENTION_POLICY_DAYS=14
This automatically deletes traces older than 14 days, so the database stays a predictable size and the UI stays fast. For most busy production apps, 7 to 14 days is enough for debugging. Only keep traces longer if you actually need old data for evaluation.
Step 9: Fix High Memory Usage and OOM Kills in Phoenix
High memory use in self-hosted Phoenix usually comes from one of these things:
- Huge batch of traces arriving at once.
- SQLite database with no size limit.
- A container that just doesn’t have enough memory for your trace volume.
Start by giving the container a realistic minimum amount of memory:
services:
phoenix:
image: arizephoenix/phoenix:latest
deploy:
resources:
limits:
memory: 4g
reservations:
memory: 2g
As a sizing rule, plan for about 1 GB of memory per million traces kept, plus 1 GB for Phoenix itself. Increase this if you keep traces longer or your trace volume grows.
If the container still crashes from running out of memory, lower PHOENIX_DEFAULT_RETENTION_POLICY_DAYS to keep fewer traces, and make sure you’ve switched from SQLite to PostgreSQL, since Postgres stores data on disk instead of in the container’s memory.
Step 10. Fix Reverse Proxy Access Issues in Phoenix
When Phoenix sits behind Nginx, Caddy, or Traefik, an “Unexpected token '<‘” error in the browser means the proxy is serving an HTML error page instead of forwarding the API response.
Set the root path variable so Phoenix knows it is running under a subpath:
export PHOENIX_HOST_ROOT_PATH="/phoenix"
Then check that your proxy config forwards the right paths, plus the UI port (6006) and, if it’s used from outside, the gRPC port (4317). Clearing your browser cache after changing the proxy also fixes many access problems.
A Repeatable Checklist for Phoenix Issues
Follow these steps in order to avoid checking the wrong thing first:
- Confirm traces exist in your app code.
- Send a manual test trace.
- Check the OTLP endpoint and ports.
- Check protocol and exporter settings.
- Check attribute size and Phoenix version.
- Check the database connection and migrations.
- Check for database locks.
- Check retention settings and disk size.
- Check container memory limits.
- Check the reverse proxy.
Using this same order every time turns it into a simple checklist your whole team can reuse for Arize Phoenix troubleshooting.
When Phoenix Needs Its Own Server
If Phoenix and your app are fighting over the same CPU, memory, or disk on one server, no amount of troubleshooting will fully fix it. The real problem is shared resources, not settings.
Moving Phoenix to its own dedicated Linux VPS gives it separate CPU and memory, so it stops competing with your app and scales more predictably.
Comparing Phoenix with Other Tracing Tools
Phoenix isn’t the only observability tool teams run, and many setups use multiple collectors for different services.
If you’re also running SigNoz alongside Phoenix, or thinking about switching to it, comparing how each tool handles OTLP ingestion, storage, and errors makes it easier to spot patterns and pick the right tool for each job.
For deployment-specific issues such as OTLP ingestion failures, ClickHouse startup loops, and high disk usage, refer to the SigNoz deployment troubleshooting guide.
Conclusion
Almost every Phoenix issue comes from your code, the network endpoint, the protocol, storage, or the server’s resources. Checking these in order, instead of guessing, turns a messy debugging session into a quick checklist.
Save this guide for the next time traces disappear, the database errors out, or memory usage climbs too high.
We hope you enjoy this Arize Phoenix troubleshooting. You can check the Arize Phoenix GitHub repository for release notes or similar issues if a problem persists.
FAQs
Why are my traces not showing up in Phoenix?
Usually the app never sent them, or the exporter points at the wrong endpoint or port. Add a console exporter to confirm traces exist, then check PHOENIX_COLLECTOR_ENDPOINT.
Why does Phoenix say the database is in a dirty state?
This means a migration stopped halfway through, usually because of a PostgreSQL version mismatch. Run alembic stamp head to reset it, then restart Phoenix.
How do I stop Phoenix from using too much memory?
Set a retention policy with PHOENIX_DEFAULT_RETENTION_POLICY_DAYS, move to PostgreSQL, and set a realistic container memory limit based on your trace volume.