{"record":{"id":"a73b28ffb62c7c88","repo":"mastra-ai/mastra","slug":"snapshot-has-mismatches-length-mismatch-mismat","errorCode":null,"errorMessage":"Snapshot has ${mismatches.length} mismatch${mismatches.length > 1 ? 'es' : ''}:\n\n${mismatchDetails}\n\nSnapshot: ${snapshotPath}\nRun with { updateSnapshot: true } to update.","messagePattern":"Snapshot has (.+?) mismatch(.+?):\n\n(.+?)\n\nSnapshot: (.+?)\nRun with (.+?) to update\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"observability/mastra/src/exporters/test.ts","lineNumber":1349,"sourceCode":"            `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) =>\n            `${i + 1}. ${m.path}\\n   Expected: ${JSON.stringify(m.expected)}\\n   Actual:   ${JSON.stringify(m.actual)}`,\n        )\n        .join('\\n\\n');\n      throw new Error(\n        `Snapshot has ${mismatches.length} mismatch${mismatches.length > 1 ? 'es' : ''}:\\n\\n` +\n          `${mismatchDetails}\\n\\n` +\n          `Snapshot: ${snapshotPath}\\n` +\n          `Run with { updateSnapshot: true } to update.`,\n      );\n    }\n  }\n\n  /**\n   * Compare two structure graphs and return differences\n   */\n  #compareStructure(actual: string[], expected: string[]): string[] {\n    const diffs: string[] = [];\n\n    const maxLen = Math.max(actual.length, expected.length);\n    for (let i = 0; i < maxLen; i++) {\n      const actualLine = actual[i];\n      const expectedLine = expected[i];","sourceCodeStart":1331,"sourceCodeEnd":1367,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/observability/mastra/src/exporters/test.ts#L1331-L1367","documentation":"After the structure check passes, assertMatchesSnapshot deep-compares the normalized span tree against the snapshot's 'spans' section using marker-aware comparison (__or__, __any__ wildcards). Each field that differs (path, expected, actual) is collected, and if any exist it throws an aggregate error listing every mismatch. Unlike error 825 this compares span content (attributes, status, names), not just shape.","triggerScenarios":"Calling assertMatchesSnapshot when span field values differ from the snapshot: changed model IDs, token counts, durations, span names, statuses, or attribute values that are not covered by __any__/__or__ markers in the snapshot.","commonSituations":"Snapshot recorded with different model or provider settings; volatile fields (usage counts, timestamps) that lack __any__ markers; locale/format changes in attribute values; stale snapshots after code changes to span attribute computation.","solutions":["Review the numbered mismatch list; fix the actual span values if the snapshot is the source of truth.","Replace brittle exact values in the snapshot with markers like {\"__any__\":\"number\"} or {\"__or__\":[...]} for volatile fields.","Re-record with { updateSnapshot: true } if the new values are the intended baseline.","Pin model/provider/test inputs so attributes are deterministic, then update the snapshot once."],"exampleFix":"// snapshot before (brittle)\n\"usage\": { \"totalTokens\": 42 }\n// snapshot after (marker for volatile field)\n\"usage\": { \"totalTokens\": { \"__any__\": \"number\" } }","handlingStrategy":"try-catch","validationCode":"const snap = JSON.parse(fs.readFileSync(snapshotPath, 'utf-8'));\n// detect volatile fields recorded as exact numbers that should use markers\nif (JSON.stringify(snap).includes('\"totalTokens\":')) console.warn('Snapshot may contain volatile token counts; consider __any__ markers');","typeGuard":"function isSnapshotValue(v: unknown): boolean {\n  if (v === null || typeof v !== 'object') return true;\n  return '__any__' in (v as object) || '__or__' in (v as object);\n}","tryCatchPattern":"try {\n  await exporter.assertMatchesSnapshot('agent-trace.snap');\n} catch (err) {\n  const msg = err instanceof Error ? err.message : String(err);\n  if (msg.startsWith('Snapshot has')) {\n    console.error(msg); // mismatch list includes per-path expected/actual\n    if (process.env.UPDATE_SNAPSHOTS) return exporter.assertMatchesSnapshot('agent-trace.snap', { updateSnapshot: true });\n  }\n  throw err;\n}","preventionTips":["Use {\"__any__\":\"number\"} / {\"__or__\":[...]} markers for volatile fields (tokens, durations, ids).","Pin model, temperature, and provider settings in tracing tests.","Update snapshots deliberately and review the diff in the PR.","Split snapshots per scenario so mismatches stay localized."],"tags":["testing","snapshot","deep-equality","spans"],"backgroundTag":"snapshot-mismatch","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}