mastra-ai/mastra · error

Structure mismatch in snapshot: Expected: ${expectedStructu

Error message

Structure mismatch in snapshot:

Expected:
${expectedStructure.join('
')}

Actual:
${structureGraph.join('
')}

Differences:
${structureMismatches.join('
')}

Snapshot: ${snapshotPath}
Run with { updateSnapshot: true } to update.

What it means

TestExporter's assertMatchesSnapshot first compares a lightweight ASCII 'structure graph' of the recorded span tree (span names/types/nesting) against the __structure__ section of the snapshot file. If any line differs, it means the shape of the traced spans changed relative to the stored snapshot, and it throws before doing the deeper field-by-field comparison. This is an intentional assertion failure, not a runtime fault.

Source

Thrown at observability/mastra/src/exporters/test.ts:1327

    if (Array.isArray(snapshotData)) {
      // Old format: just the spans array
      expectedSpans = snapshotData;
    } else if (snapshotData && typeof snapshotData === 'object' && 'spans' in snapshotData) {
      // New format: { __structure__, spans }
      expectedSpans = snapshotData.spans;
      expectedStructure = snapshotData.__structure__;
    } else {
      throw new Error(
        `Invalid snapshot format in ${snapshotPath}.\n` + `Expected an array or object with 'spans' property.`,
      );
    }

    // Compare structure first (quick validation)
    if (expectedStructure) {
      const structureMismatches = this.#compareStructure(structureGraph, expectedStructure);
      if (structureMismatches.length > 0) {
        throw new Error(
          `Structure mismatch in snapshot:\n\n` +
            `Expected:\n${expectedStructure.join('\n')}\n\n` +
            `Actual:\n${structureGraph.join('\n')}\n\n` +
            `Differences:\n${structureMismatches.join('\n')}\n\n` +
            `Snapshot: ${snapshotPath}\n` +
            `Run with { updateSnapshot: true } to update.`,
        );
      }
    }

    // Deep compare spans
    const mismatches: { path: string; expected: unknown; actual: unknown }[] = [];
    this.#deepCompareWithMarkers(normalizedTree, expectedSpans, '$.spans', mismatches);

    if (mismatches.length > 0) {
      const mismatchDetails = mismatches
        .map(
          (m, i) =>

View on GitHub (pinned to 75dd419e61)

Solutions

  1. If the new structure is correct, re-record with exporter.assertMatchesSnapshot(name, { updateSnapshot: true }).
  2. Diff the 'Expected' vs 'Actual' trees in the message to find which span appears, disappears, or moved, and fix the test or traced code accordingly.
  3. If the change came from a Mastra upgrade, regenerate all tracing snapshots as part of the upgrade and commit them.
  4. Make the traced operation deterministic (fixed model output, fixed tool results) so the span tree is stable across runs.

Example fix

// before
await exporter.assertMatchesSnapshot('agent-trace.snap');
// after (intentional structural change)
await exporter.assertMatchesSnapshot('agent-trace.snap', { updateSnapshot: true });
Defensive patterns

Strategy: try-catch

Validate before calling

const snap = JSON.parse(fs.readFileSync(path.join('__snapshots__', name), 'utf-8'));
if (!snap || !Array.isArray(snap.__structure__)) throw new Error('Snapshot missing __structure__; re-record it');

Type guard

function hasStructure(s: unknown): s is { __structure__: string[]; spans: unknown } {
  return typeof s === 'object' && s !== null && 'spans' in s && Array.isArray((s as any).__structure__);
}

Try / catch

try {
  await exporter.assertMatchesSnapshot('agent-trace.snap');
} catch (err) {
  if (String(err.message).startsWith('Structure mismatch in snapshot')) {
    // print diff, optionally auto-update in a local flag mode
    if (process.env.UPDATE_SNAPSHOTS) return exporter.assertMatchesSnapshot('agent-trace.snap', { updateSnapshot: true });
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling exporter.assertMatchesSnapshot(name) when the generated structureGraph differs from snapshotData.__structure__ — e.g. the AI operation created different spans, a new/removed nesting level, renamed span types, or the snapshot was generated by an older @mastra/observability version.

Common situations: Upgrading Mastra and running stale snapshots; adding/removing a tool call, workflow step, or LLM call that changes span nesting; non-deterministic agent behavior producing different child spans; hand-editing a snapshot and breaking the __structure__ block.

Related errors


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