mastra-ai/mastra · error · Error

Persisted score is missing spanId for traceId: ${target.trac

Error message

Persisted score is missing spanId for traceId: ${target.traceId}

What it means

In scoreTraceBatch, after a scorer runs, the persisted spanId is resolved as score.spanId ?? target.spanId. If both are absent, this Error is thrown because a persisted score row must be attributable to a span. It indicates the scorer run produced a score without a span association and the caller did not supply one either.

Source

Thrown at packages/core/src/evals/scoreTraces/scoreTracesWorkflow.ts:337

  failedCount: number;
  results: ScoreTraceBatchResult[];
}> {
  const results = await pMap(
    targets,
    async (target, index): Promise<ScoreTraceBatchResult> => {
      try {
        const score = await scoreTrace({
          storage,
          scorer,
          target,
          batchId,
          datasetId,
          datasetItemId: target.datasetItemId,
        });
        const spanId = score.spanId ?? target.spanId;

        if (!spanId) {
          throw new Error(`Persisted score is missing spanId for traceId: ${target.traceId}`);
        }

        return {
          ok: true,
          index,
          traceId: score.traceId ?? target.traceId,
          spanId,
          ...(target.datasetItemId ? { datasetItemId: target.datasetItemId } : {}),
          score,
        };
      } catch (error) {
        return {
          ok: false,
          index,
          traceId: target.traceId,
          ...(target.spanId ? { spanId: target.spanId } : {}),
          ...(target.datasetItemId ? { datasetItemId: target.datasetItemId } : {}),
          error: toBatchResultError(error),

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Always include spanId in the score target: { traceId, spanId } resolved via resolveTargetSpan/root span.
  2. Check why score.spanId was undefined — ensure the scorer ran with trace/span context (not a bare scorer.run without ids).
  3. Update custom scorer code to propagate spanId into its returned score.
  4. Persist traces fully so span resolution succeeds before batch scoring.
  5. Validate targets before batch scoring to fail fast on missing spanId.

Example fix

// before
const targets = traces.map(t => ({ traceId: t.traceId }));
// after
const targets = traces.map(t => ({ traceId: t.traceId, spanId: t.spans.find(s => s.parentSpanId === null)?.spanId }));
Defensive patterns

Strategy: validation

Validate before calling

// require spanId on batch targets up front
targets.forEach(t => {
  if (!t.spanId) throw new Error(`Target for trace ${t.traceId} is missing spanId`);
});

Type guard

function hasSpanId(target) {
  return typeof target.spanId === 'string' && target.spanId.length > 0;
}

Try / catch

try {
  const results = await scoreTraceBatchTargets(targets);
} catch (e) {
  if (typeof e.message === 'string' && e.message.startsWith('Persisted score is missing spanId')) {
    console.error('Scorer dropped span metadata — run scorers with trace/span context');
  }
  throw e;
}

Prevention

When it happens

Trigger: Batch scoring trace targets where the scorer's run() result has no spanId (scorer invoked without span context) and the target { traceId } was given without spanId — e.g. the trace's span resolution was skipped or the scorer dropped span metadata.

Common situations: Scorer implementations returning custom results that omit spanId; targets built manually with only traceId; traces whose spans failed to resolve earlier but scoring proceeded; custom scorer pipelines bypassing runScorerForTrace's tenancy threading.

Related errors


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