mastra-ai/mastra · warning · HTTPException

Span not found

Error message

Span not found

What it means

The span endpoint resolves a single span via `observabilityStore.getSpan({ traceId, spanId })`; when nothing is returned the handler throws a 404 'Span not found'. Both the trace and the specific span ID must exist in the store.

Source

Thrown at packages/server/src/server/handlers/observability.ts:347

/** Route: GET /observability/traces/:traceId/spans/:spanId - get a single span with full details. */
export const GET_SPAN_ROUTE: ServerRoute = createRoute({
  method: 'GET',
  path: '/observability/traces/:traceId/spans/:spanId',
  responseType: 'json',
  pathParamSchema: getSpanArgsSchema,
  responseSchema: getSpanResponseSchema,
  summary: 'Get a single span by ID',
  description: 'Returns a complete span record with all details by trace ID and span ID',
  tags: ['Observability'],
  requiresAuth: true,
  handler: async ({ mastra, traceId, spanId }) => {
    try {
      const observabilityStore = await getObservabilityStore(mastra);
      const span = await observabilityStore.getSpan({ traceId, spanId });

      if (!span) {
        throw new HTTPException(404, { message: `Span not found` });
      }

      return span;
    } catch (error) {
      return handleError(error, 'Error getting span');
    }
  },
});

/** Route: GET /observability/traces/:traceId/trajectory - extract trajectory from a trace. */
export const GET_TRACE_TRAJECTORY_ROUTE = createRoute({
  method: 'GET',
  path: '/observability/traces/:traceId/trajectory',
  responseType: 'json',
  pathParamSchema: getTraceArgsSchema,
  responseSchema: z.object({
    steps: z.array(z.unknown()),
    totalDurationMs: z.number().optional(),

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Fetch the full trace first and pick a spanId from its spans array.
  2. Confirm the spanId belongs to the given traceId (IDs are not globally unique).
  3. Check the storage backend for ingestion gaps or write errors.
  4. Return a graceful 'span unavailable' UI state on 404.

Example fix

// before
const span = await fetch(`/api/observability/traces/${traceId}/spans/${spanId}`).then(r => r.json());
// after
const trace = await fetch(`/api/observability/traces/${traceId}`).then(r => r.json());
const span = trace.spans.find(s => s.id === spanId);
if (!span) throw new Error(`Span ${spanId} not in trace ${traceId}`);
Defensive patterns

Strategy: validation

Validate before calling

const trace = await getTrace(traceId);
if (!trace.spans.some(s => s.id === spanId)) {
  throw new Error(`Span ${spanId} not in trace ${traceId}`);
}

Type guard

function hasSpan(trace: { spans: { id: string }[] }, spanId: string): boolean {
  return trace.spans.some(s => s.id === spanId);
}

Try / catch

try {
  return await getSpan(traceId, spanId);
} catch (e) {
  if (is404(e)) return null; // span unavailable
  throw e;
}

Prevention

When it happens

Trigger: Calling GET /api/observability/traces/:traceId/spans/:spanId where the spanId doesn't exist under that trace — wrong span ID, span from a different trace, or partial ingestion (trace exists but span wasn't persisted).

Common situations: Referencing a span ID from logs of a different trace; storage write failures dropped individual spans; querying in-progress traces before the span was flushed.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/82101e497748856c. Report an issue: GitHub.