mastra-ai/mastra · error · MastraError

OBSERVABILITY_SPAN_ID_REQUIRED

OBSERVABILITY_SPAN_ID_REQUIRED

Error message

Span ID is required for creating a span

What it means

validateCreateSpan enforces that every span record persisted to the in-memory observability store carries a spanId; spans without one cannot be keyed inside their trace. createSpan and batchCreateSpans throw this SYSTEM-category error when record.spanId is falsy.

Source

Thrown at packages/core/src/storage/domains/observability/inmemory.ts:468

    this.upsertSpanToTrace(record);
  }

  async batchCreateSpans(args: BatchCreateSpansArgs): Promise<void> {
    const now = new Date();
    for (const span of args.records) {
      this.validateCreateSpan(span);
      const record: SpanRecord = {
        ...span,
        createdAt: now,
        updatedAt: now,
      };
      this.upsertSpanToTrace(record);
    }
  }

  private validateCreateSpan(record: CreateSpanRecord): void {
    if (!record.spanId) {
      throw new MastraError({
        id: 'OBSERVABILITY_SPAN_ID_REQUIRED',
        domain: ErrorDomain.MASTRA_OBSERVABILITY,
        category: ErrorCategory.SYSTEM,
        text: 'Span ID is required for creating a span',
      });
    }

    if (!record.traceId) {
      throw new MastraError({
        id: 'OBSERVABILITY_TRACE_ID_REQUIRED',
        domain: ErrorDomain.MASTRA_OBSERVABILITY,
        category: ErrorCategory.SYSTEM,
        text: 'Trace ID is required for creating a span',
      });
    }
  }

  /**

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Populate spanId on every span before calling createSpan/batchCreateSpans (e.g. crypto.randomUUID()).
  2. When importing from another tracing system, map its span-id field to spanId explicitly.
  3. Filter or fix records missing spanId before batch submission instead of letting one bad record abort the batch.
  4. Verify the span object is not being spread from a source that omits/span-renames the id.

Example fix

// before
await storage.createSpan({ traceId, name: 'llm-call' }); // throws

// after
await storage.createSpan({ traceId, spanId: crypto.randomUUID(), name: 'llm-call' });
Defensive patterns

Strategy: validation

Validate before calling

function assertSpanRecord(r: CreateSpanRecord): void {
  if (!r.spanId) throw new Error('spanId is required');
  if (!r.traceId) throw new Error('traceId is required');
}
spans.forEach(assertSpanRecord);
await storage.batchCreateSpans(spans);

Type guard

function isCreateableSpan(r: CreateSpanRecord): r is CreateSpanRecord & { spanId: string; traceId: string } {
  return Boolean(r.spanId) && Boolean(r.traceId);
}

Try / catch

try {
  await storage.createSpan(record);
} catch (e) {
  if ((e as MastraError).id === 'OBSERVABILITY_SPAN_ID_REQUIRED') {
    logger.error('Span dropped: missing spanId', record);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling createSpan or batchCreateSpans with a CreateSpanRecord lacking spanId (undefined, null, or empty string).

Common situations: Mapping external tracing data (OTel, custom tracers) where the span id field has a different name; dropping fields during serialization; constructing spans manually in tests; a tracer bug emitting spans before assigning ids.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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