LlamaIndex observability — instrumentation, LlamaCloud, Arize, and Langfuse (2026) — Fix Guide (2026) | AI Error Hub
Home Providers LlamaIndex Observability
LlamaIndex Observability · Tracing Severity: Low HTTP n/a

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.

By Sana K. · Cloud AI Reliability Engineer Published 2026-07-26 Verified 2026-07-26

Quick fix (TL;DR)

Resolution: LlamaIndex uses the modern instrumentation API (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.

Traces not appearing in Arize Phoenix
# import phoenix as px
# px.launch_app()
# Ran query — nothing in Phoenix UI
# Missing: OpenInference LlamaIndex instrumentation
Langfuse traces missing async spans
# langfuse_handler = LlamaIndexCallbackHandler(...)
# Ran async query — some spans missing
# Callback handler does not propagate through async fully
LlamaCloud trace project not found
LlamaCloudError: Project "my-app" not found. Create the project in the LlamaCloud UI first.

Reference

Observability integration options

PlatformPackageNotes
Arize Phoenix (OSS)arize-phoenix + openinference-instrumentation-llama-indexLocal UI; open-source
Arize (managed)Same instrumentation, managed backendProduction-grade
LangfuselangfuseOSS + managed cloud
LlamaCloudllama-cloud-servicesLlamaIndex's own tracing
Weights & BiaseswandbFor ML-team-first orgs
OpenTelemetry directopeninference-* + OTLP exporterFor 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

Fix #1

Set up Arize Phoenix locally for dev observability

The fastest path to seeing every LLM call and retrieval.

Phoenix is the local, open-source observability UI. Launch it, install the OpenInference LlamaIndex instrumentation, initialize before building components.

phoenix_setup.py
# 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
For production, switch the endpoint to managed Arize or self-hosted Phoenix. The instrumentation is unchanged; only the exporter destination changes.
Fix #2

Langfuse for managed observability with cost + eval

Cost tracking + prompt versioning + observability in one.

Langfuse is another OSS option with managed cloud. Same instrumentation pattern; different destination.

langfuse_setup.py
# 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
Langfuse adds cost per LLM call and prompt versioning on top of tracing. If you want observability + prompt management in one, it is a strong choice.
Fix #3

Use the instrumentation dispatcher for custom exporters

When no off-the-shelf exporter fits, hook into events directly.

LlamaIndex's llama_index.core.instrumentation provides the raw dispatcher. Attach custom event handlers to ship traces to any backend.

custom_instrumentation.py
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())
For most teams, the packaged integrations (Phoenix, Langfuse, Arize) are enough. Reach for the raw instrumentation API only when you have specific requirements not covered.

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

The instrumentation API (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.
Minimal — spans are recorded in background threads and exported in batches. On serverless with cold starts, initial trace upload can add 100-300ms; not significant thereafter.
Phoenix for local dev (free, easy). Arize for managed with LLM-specific features. Langfuse for observability + prompt management + cost tracking. LlamaCloud for LlamaIndex-native. Choose based on team familiarity and specific features.
Yes — the OpenInference LlamaIndex instrumentation is built on OpenTelemetry. Point the OTLP exporter at any OpenTelemetry-compatible backend (Jaeger, Datadog, Honeycomb, etc.).
Use the OpenTelemetry SpanProcessor to inspect and modify spans before export. Or configure your platform's built-in redaction. LlamaCloud offers automatic PII detection at ingest.

Get the weekly AI-error digest

New fixes, provider status recaps, and one deep tutorial — every Tuesday. 8,400+ engineers.