{"record":{"id":"cf0f6909ccaee95f","repo":"denoland/deno","slug":"snapshot-serializer-must-return-a-string","errorCode":null,"errorMessage":"Snapshot serializer must return a string","messagePattern":"Snapshot serializer must return a string","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"cli/js/40_test_snapshot.js","lineNumber":337,"sourceCode":"    throw new TypeError(\n      \"Expected the second argument to assertSnapshot() to be an options object or a message string\",\n    );\n  }\n\n  const context = getSnapshotContext(options);\n  const testName = options.name ?? getFullTestName(tContext);\n  const count = (MapPrototypeGet(context.counts, testName) ?? 0) + 1;\n  MapPrototypeSet(context.counts, testName, count);\n  const name = `${testName} ${count}`;\n\n  if (!ArrayPrototypeIncludes(context.updateQueue, name)) {\n    ArrayPrototypePush(context.updateQueue, name);\n  }\n\n  const serializer = options.serializer ?? serialize;\n  const actualSnapshot = serializer(actual);\n  if (typeof actualSnapshot !== \"string\") {\n    throw new TypeError(\"Snapshot serializer must return a string\");\n  }\n\n  const expectedSnapshot = MapPrototypeGet(context.currentValues, name);\n\n  if (getIsUpdateMode()) {\n    if (actualSnapshot !== expectedSnapshot) {\n      MapPrototypeSet(context.updatedValues, name, actualSnapshot);\n      if (!ArrayPrototypeIncludes(context.updatedNames, name)) {\n        ArrayPrototypePush(context.updatedNames, name);\n      }\n    }\n    return;\n  }\n\n  if (!context.fileExists) {\n    throw new AssertionError(\n      getErrorMessage(\"Missing snapshot file.\", options),\n    );","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/cli/js/40_test_snapshot.js#L319-L355","documentation":"assertSnapshot serializes the actual value with options.serializer (or the built-in serialize) and requires the result to be a string before comparing it to the stored snapshot (cli/js/40_test_snapshot.js). If a custom serializer returns a number, object, or undefined, this TypeError is thrown at assertion time. Note that JSON.stringify — a common serializer choice — returns undefined for top-level undefined, null is fine, but symbols/functions also stringify to undefined.","triggerScenarios":"`t.assertSnapshot(v, { serializer: (x) => x.count })` (returns a number), `{ serializer: JSON.stringify }` when the value is undefined, or any serializer that forgets to stringify its result.","commonSituations":"Writing a compact custom serializer that extracts a field and forgets to convert it to a string; using JSON.stringify on values it cannot serialize at top level; changing a serializer's return type during a refactor.","solutions":["Make the serializer return a string: wrap the result with String(...) or JSON.stringify(...).","Drop the custom serializer to use the built-in default, which always returns a string.","After fixing the serializer, regenerate snapshots with `deno test --update` if the output format changed."],"exampleFix":"// before\nawait t.assertSnapshot(state, { serializer: (s) => s.items.length });\n\n// after\nawait t.assertSnapshot(state, { serializer: (s) => String(s.items.length) });","handlingStrategy":"type-guard","validationCode":"// Wrap any custom serializer so it always returns a string:\nfunction strSerializer(fn) {\n  return (value) => {\n    const out = fn(value);\n    return typeof out === \"string\" ? out : JSON.stringify(out);\n  };\n}\nawait t.assertSnapshot(value, { serializer: strSerializer(mySerializer) });","typeGuard":"/** @param {unknown} s @returns {s is string} */\nconst isString = (s) => typeof s === \"string\";","tryCatchPattern":null,"preventionTips":["End every custom serializer with an explicit String(...) or JSON.stringify(...) return.","Beware JSON.stringify returning undefined for top-level undefined/symbol/function values.","If the serializer's output format changes, regenerate snapshots with `deno test --update`."],"tags":["deno","deno-test","snapshot","serializer","typeerror"],"backgroundTag":"custom-serializer-return-type","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}