LlamaIndex observability — traces missing, exporters not firing
Debugging LlamaIndex without traces is painful. The instrumentation API integrates with OpenInference-compatible platforms (Arize, Langfuse, Phoenix) and LlamaIndex's own LlamaCloud tracing.
Quick fix (TL;DR)
llama_index.core.instrumentation) and older callback managers. Fix missing traces by (a) installing the platform integration package (arize-phoenix, langfuse, or llama-cloud-services), (b) initializing the exporter BEFORE building components, and (c) understanding the event types you care about (LLM, retrieval, agent step).Real error messages you'll see
These are the exact strings returned by the LlamaIndex framework and its integrations when this error occurs. Copy-paste-searching any of them should land on this page.
# import phoenix as px # px.launch_app() # Ran query — nothing in Phoenix UI # Missing: OpenInference LlamaIndex instrumentation
# langfuse_handler = LlamaIndexCallbackHandler(...) # Ran async query — some spans missing # Callback handler does not propagate through async fully
LlamaCloudError: Project "my-app" not found. Create the project in the LlamaCloud UI first.
Reference
Observability integration options
| Platform | Package | Notes |
|---|---|---|
| Arize Phoenix (OSS) | arize-phoenix + openinference-instrumentation-llama-index | Local UI; open-source |
| Arize (managed) | Same instrumentation, managed backend | Production-grade |
| Langfuse | langfuse | OSS + managed cloud |
| LlamaCloud | llama-cloud-services | LlamaIndex's own tracing |
| Weights & Biases | wandb | For ML-team-first orgs |
| OpenTelemetry direct | openinference-* + OTLP exporter | For custom / self-hosted observability |
Root causes, ranked by frequency
Based on developer reports across LlamaIndex forums, GitHub issues, and Discord community during 2025–2026.
- 25%Instrumentation not initialized before components created. Spans do not attach to already-existing objects.
- 18%Wrong integration package for the platform. Installed old callback-based Langfuse when instrumentation-API version is needed.
- 14%Async context not propagated. Spans lost across await boundaries.
- 10%Missing env vars for the exporter. Langfuse SECRET_KEY, PUBLIC_KEY not set.
- 8%Serverless: no flush before exit. Lambda function exits before traces upload.
- 7%Sampling rate=0. Set to 0 during load test; forgotten.
- 7%Nested spans not fitting exporter schema. Custom span types dropped by exporter.
- 11%LlamaCloud project not configured. Trace destination not created.
Fixes — copy-paste solutions
Set up Arize Phoenix locally for dev observability
Phoenix is the local, open-source observability UI. Launch it, install the OpenInference LlamaIndex instrumentation, initialize before building components.
# pip install arize-phoenix openinference-instrumentation-llama-index # --- Initialize BEFORE building components --- import phoenix as px # Launch the local Phoenix UI at http://localhost:6006 px.launch_app() # Set up the LlamaIndex instrumentation from phoenix.otel import register tracer_provider = register( project_name="my-app-dev", endpoint="http://localhost:6006/v1/traces", # local Phoenix ) from openinference.instrumentation.llama_index import LlamaIndexInstrumentor LlamaIndexInstrumentor().instrument(tracer_provider=tracer_provider) # --- NOW build components --- from llama_index.core import VectorStoreIndex from llama_index.llms.openai import OpenAI llm = OpenAI(model="gpt-4o-mini") index = VectorStoreIndex.from_documents(docs, embed_model=embed_model) query_engine = index.as_query_engine(llm=llm, similarity_top_k=6) # Every LLM call, embedding call, and retrieval will now appear in Phoenix response = query_engine.query("What is the refund policy?") # Open http://localhost:6006 to see: # - Traces tree per query # - LLM inputs/outputs # - Retrieved node scores # - Timing per step # - Cost estimates
Langfuse for managed observability with cost + eval
Langfuse is another OSS option with managed cloud. Same instrumentation pattern; different destination.
# pip install langfuse openinference-instrumentation-llama-index import os os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..." os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # or self-hosted from langfuse import Langfuse from langfuse.llama_index import LlamaIndexCallbackHandler # Newer OpenInference-based path from openinference.instrumentation.llama_index import LlamaIndexInstrumentor # LlamaIndex will export via OTLP to Langfuse's OpenTelemetry endpoint from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter tracer_provider = TracerProvider() otlp_exporter = OTLPSpanExporter( endpoint=f"{os.environ['LANGFUSE_HOST']}/api/public/otel/v1/traces", headers={"Authorization": f"Basic {base64.b64encode(f'{os.environ['LANGFUSE_PUBLIC_KEY']}:{os.environ['LANGFUSE_SECRET_KEY']}'.encode()).decode()}"}, ) tracer_provider.add_span_processor(BatchSpanProcessor(otlp_exporter)) trace.set_tracer_provider(tracer_provider) LlamaIndexInstrumentor().instrument(tracer_provider=tracer_provider) # --- Now use LlamaIndex normally --- response = query_engine.query("What is the refund policy?") # --- For serverless: flush before exit --- def flush_traces(): tracer_provider.force_flush(timeout_millis=5000) import atexit atexit.register(flush_traces) # Traces appear in Langfuse UI with cost, latency, and full span tree
Use the instrumentation dispatcher for custom exporters
LlamaIndex's llama_index.core.instrumentation provides the raw dispatcher. Attach custom event handlers to ship traces to any backend.
from llama_index.core.instrumentation import get_dispatcher from llama_index.core.instrumentation.event_handlers import BaseEventHandler from llama_index.core.instrumentation.events import ( LLMChatStartEvent, LLMChatEndEvent, EmbeddingEndEvent, RetrievalStartEvent, RetrievalEndEvent, ) import time import json class CustomLoggingHandler(BaseEventHandler): """Ship every event to your own logging / observability.""" def handle(self, event) -> None: payload = { "timestamp": time.time(), "type": type(event).__name__, "id": event.id_, } if isinstance(event, LLMChatStartEvent): payload["messages"] = [str(m) for m in event.messages] elif isinstance(event, LLMChatEndEvent): payload["response"] = str(event.response) if event.response else None elif isinstance(event, RetrievalEndEvent): payload["num_nodes"] = len(event.nodes) if event.nodes else 0 payload["top_score"] = event.nodes[0].score if event.nodes else None # Ship to your log aggregator / message queue my_logger.info(json.dumps(payload)) @classmethod def class_name(cls) -> str: return "CustomLoggingHandler" # --- Attach to the global dispatcher --- dispatcher = get_dispatcher() dispatcher.add_event_handler(CustomLoggingHandler()) # --- Now every LlamaIndex event flows to your handler --- response = query_engine.query("...") # --- For per-request scoped context, use span handlers --- from llama_index.core.instrumentation.span_handlers import BaseSpanHandler class RequestScopedSpanHandler(BaseSpanHandler): def new_span(self, id_: str, bound_args, instance, parent_span_id=None, **kwargs): # Attach request_id from a context var to every span # (use contextvars.ContextVar to thread through async) pass def prepare_to_exit_span(self, id_, bound_args, instance, result=None, **kwargs): pass def prepare_to_drop_span(self, id_, bound_args, instance, err=None, **kwargs): pass @classmethod def class_name(cls) -> str: return "RequestScopedSpanHandler" dispatcher.add_span_handler(RequestScopedSpanHandler())
Prevention checklist
Ship these seven safeguards once and this error stops appearing in your logs.
- Initialize instrumentation BEFORE constructing any LlamaIndex components.
- Install the OpenInference LlamaIndex instrumentation package.
- For managed platforms (Arize, Langfuse, LlamaCloud), set credentials via env vars.
- For serverless, flush traces before function exit.
- Use project names to separate dev / staging / prod traces.
- Sample production traces if volume is huge; do not trace 100% blindly.
- Test traces appear in your platform after every major dependency upgrade.
Frequently asked questions
llama_index.core.instrumentation) is the newer, more structured system with events and spans. Callback managers are legacy but still work. New integrations target instrumentation.Related errors & hubs
Get the weekly AI-error digest
New fixes, provider status recaps, and one deep tutorial — every Tuesday. 8,400+ engineers.