{"record":{"id":"51a33ce79898c8d0","repo":"mastra-ai/mastra","slug":"structure-mismatch-in-snapshot-expected-expec","errorCode":null,"errorMessage":"Structure mismatch in snapshot:\n\nExpected:\n${expectedStructure.join('\n')}\n\nActual:\n${structureGraph.join('\n')}\n\nDifferences:\n${structureMismatches.join('\n')}\n\nSnapshot: ${snapshotPath}\nRun with { updateSnapshot: true } to update.","messagePattern":"Structure mismatch in snapshot:\n\nExpected:\n(.+?)\n\nActual:\n(.+?)\n\nDifferences:\n(.+?)\n\nSnapshot: (.+?)\nRun with (.+?) to update\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"observability/mastra/src/exporters/test.ts","lineNumber":1327,"sourceCode":"\n    if (Array.isArray(snapshotData)) {\n      // Old format: just the spans array\n      expectedSpans = snapshotData;\n    } else if (snapshotData && typeof snapshotData === 'object' && 'spans' in snapshotData) {\n      // New format: { __structure__, spans }\n      expectedSpans = snapshotData.spans;\n      expectedStructure = snapshotData.__structure__;\n    } else {\n      throw new Error(\n        `Invalid snapshot format in ${snapshotPath}.\\n` + `Expected an array or object with 'spans' property.`,\n      );\n    }\n\n    // Compare structure first (quick validation)\n    if (expectedStructure) {\n      const structureMismatches = this.#compareStructure(structureGraph, expectedStructure);\n      if (structureMismatches.length > 0) {\n        throw new Error(\n          `Structure mismatch in snapshot:\\n\\n` +\n            `Expected:\\n${expectedStructure.join('\\n')}\\n\\n` +\n            `Actual:\\n${structureGraph.join('\\n')}\\n\\n` +\n            `Differences:\\n${structureMismatches.join('\\n')}\\n\\n` +\n            `Snapshot: ${snapshotPath}\\n` +\n            `Run with { updateSnapshot: true } to update.`,\n        );\n      }\n    }\n\n    // Deep compare spans\n    const mismatches: { path: string; expected: unknown; actual: unknown }[] = [];\n    this.#deepCompareWithMarkers(normalizedTree, expectedSpans, '$.spans', mismatches);\n\n    if (mismatches.length > 0) {\n      const mismatchDetails = mismatches\n        .map(\n          (m, i) =>","sourceCodeStart":1309,"sourceCodeEnd":1345,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/observability/mastra/src/exporters/test.ts#L1309-L1345","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["If the new structure is correct, re-record with exporter.assertMatchesSnapshot(name, { updateSnapshot: true }).","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.","If the change came from a Mastra upgrade, regenerate all tracing snapshots as part of the upgrade and commit them.","Make the traced operation deterministic (fixed model output, fixed tool results) so the span tree is stable across runs."],"exampleFix":"// before\nawait exporter.assertMatchesSnapshot('agent-trace.snap');\n// after (intentional structural change)\nawait exporter.assertMatchesSnapshot('agent-trace.snap', { updateSnapshot: true });","handlingStrategy":"try-catch","validationCode":"const snap = JSON.parse(fs.readFileSync(path.join('__snapshots__', name), 'utf-8'));\nif (!snap || !Array.isArray(snap.__structure__)) throw new Error('Snapshot missing __structure__; re-record it');","typeGuard":"function hasStructure(s: unknown): s is { __structure__: string[]; spans: unknown } {\n  return typeof s === 'object' && s !== null && 'spans' in s && Array.isArray((s as any).__structure__);\n}","tryCatchPattern":"try {\n  await exporter.assertMatchesSnapshot('agent-trace.snap');\n} catch (err) {\n  if (String(err.message).startsWith('Structure mismatch in snapshot')) {\n    // print diff, optionally auto-update in a local flag mode\n    if (process.env.UPDATE_SNAPSHOTS) return exporter.assertMatchesSnapshot('agent-trace.snap', { updateSnapshot: true });\n  }\n  throw err;\n}","preventionTips":["Regenerate snapshots whenever you upgrade @mastra/observability.","Keep traced test operations deterministic (mock model/tool output).","Review __structure__ diffs in CI before blanket-updating snapshots.","Treat updateSnapshot runs as reviewed changes, not test fixes."],"tags":["testing","snapshot","observability","spans"],"backgroundTag":"snapshot-mismatch","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}