{"record":{"id":"52b769997b7cea4e","repo":"Automattic/harper","slug":"unhandled-case-type-undefined","errorCode":null,"errorMessage":"Unhandled case: type undefined","messagePattern":"Unhandled case: type undefined","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/harper.js/src/Serializer.ts","lineNumber":86,"sourceCode":"\t\t\tcase 'bigint':\n\t\t\t\treturn { json: arg.toString(), type: argType };\n\t\t}\n\n\t\tif (arg.to_json !== undefined) {\n\t\t\tconst json = arg.to_json();\n\t\t\tlet type: SerializableTypes | undefined;\n\t\t\tconst constructorName = arg.constructor?.name;\n\n\t\t\tif (arg instanceof Lint || constructorName === 'Lint') {\n\t\t\t\ttype = 'Lint';\n\t\t\t} else if (arg instanceof Suggestion || constructorName === 'Suggestion') {\n\t\t\t\ttype = 'Suggestion';\n\t\t\t} else if (arg instanceof Span || constructorName === 'Span') {\n\t\t\t\ttype = 'Span';\n\t\t\t}\n\n\t\t\tif (type === undefined) {\n\t\t\t\tthrow new Error('Unhandled case: type undefined');\n\t\t\t}\n\n\t\t\treturn { json, type };\n\t\t}\n\n\t\tif (argType == 'object') {\n\t\t\treturn {\n\t\t\t\tjson: JSON.stringify(\n\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\tObject.entries(arg).map(([key, value]) => this.serializeArg([key, value])),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\ttype: 'object',\n\t\t\t};\n\t\t}\n\n\t\tthrow new Error(`Unhandled case: ${arg}`);\n\t}","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/Automattic/harper/blob/5fe7d5ab76492d83f3ecdbc3f1da83c75dcb6f83/packages/harper.js/src/Serializer.ts#L68-L104","documentation":"WorkerLinter serializes every RPC argument with Serializer.serializeArg. Arguments carrying a to_json() method (WASM-bound objects) must be recognizable as a Lint, Suggestion, or Span; if an object exposes to_json() but its class/constructor is none of those three, the serializer cannot pick a wire type tag and throws 'Unhandled case: type undefined'. This guards against silently mis-typing WASM objects crossing the worker boundary.","triggerScenarios":"Calling any WorkerLinter method (lint, applySuggestion, etc.) passing a WASM-bound object with a to_json() method whose class is not Lint, Suggestion, or Span — e.g. a custom/mis-minified class name breaking the constructorName === fallback, a stale or mismatched harper-wasm binary version, or wrapping a WASM object in a subclass.","commonSituations":"Bundlers/minifiers (Terser, esbuild) renaming the Lint/Span/Suggestion constructors so constructorName no longer matches and instanceof fails against a different WASM instance; mixing harper.js and harper-wasm versions; passing non-standard Harper objects into linter calls.","solutions":["Check that the argument is actually a harper-wasm Lint, Suggestion, or Span from the same WASM binary the WorkerLinter was created with","Ensure your bundler does not mangle class names of harper-wasm exports (configure keep_fnames / class-name preservation)","Align harper.js and harper-wasm package versions (same release line)","Pass only primitives, plain objects/arrays, or documented Harper types to WorkerLinter methods"],"exampleFix":"// before\nlinter.lint(\"text\", [someUnknownWasmObject]);\n// after\nimport { Span } from 'harper.js';\nconst span = new Span(...); // a real Span from the same harper-wasm build\nlinter.lint(\"text\", [span]);","handlingStrategy":"type-guard","validationCode":"const SUPPORTED = ['Lint', 'Span', 'Suggestion'];\nfunction isSerializableHarperObject(arg: unknown): boolean {\n  const anyArg = arg as any;\n  return typeof anyArg?.to_json !== 'function' ||\n    SUPPORTED.includes(anyArg?.constructor?.name);\n}\nargs.every(isSerializableHarperObject) || console.error('unserializable arg', args);","typeGuard":"function isKnownWasmType(arg: any): arg is Lint | Span | Suggestion {\n  return ['Lint', 'Span', 'Suggestion'].includes(arg?.constructor?.name);\n}","tryCatchPattern":"try {\n  await linter.lint(text, args);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Unhandled case: type undefined') {\n    console.error('Non-serializable WASM object passed to WorkerLinter:', args);\n  }\n  throw e;\n}","preventionTips":["Only pass primitives, plain objects/arrays, or documented Harper types to WorkerLinter methods","Keep harper.js and harper-wasm versions in lockstep","Configure your minifier to preserve harper-wasm class names","Wrap linter calls in a small typed API surface rather than passing arbitrary values"],"tags":["serialization","wasm","worker","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"5fe7d5ab76492d83f3ecdbc3f1da83c75dcb6f83","analyzedAt":"2026-09-06T11:34:38.610Z","contentChangedAt":"2026-09-06T11:34:38.610Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}