{"record":{"id":"1aca054ce1bf0945","repo":"sveltejs/kit","slug":"param-matcher-must-return-a-string-number-boolea","errorCode":null,"errorMessage":"Param matcher must return a string, number, boolean, or bigint","messagePattern":"Param matcher must return a string, number, boolean, or bigint","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/kit/src/utils/routing.js","lineNumber":162,"sourceCode":"\tconst result = matcher['~standard'].validate(value);\n\n\tif (result instanceof Promise) {\n\t\tthrow new Error('Async param matchers are not supported');\n\t}\n\n\tif (result.issues) {\n\t\treturn { success: false };\n\t}\n\n\tconst parsed = result.value;\n\n\tif (\n\t\ttypeof parsed !== 'string' &&\n\t\ttypeof parsed !== 'number' &&\n\t\ttypeof parsed !== 'boolean' &&\n\t\ttypeof parsed !== 'bigint'\n\t) {\n\t\tthrow new Error('Param matcher must return a string, number, boolean, or bigint');\n\t}\n\n\treturn { success: true, value: parsed };\n}\n\n/**\n * @param {RegExpMatchArray} match\n * @param {import('types').RouteParam[]} params\n * @param {Record<string, ParamMatcher>} matchers\n */\nexport function exec(match, params, matchers) {\n\t/** @type {Record<string, any>} */\n\tconst result = {};\n\n\tconst values = match.slice(1);\n\tconst values_needing_match = values.filter((value) => value !== undefined);\n\n\tlet buffered = 0;","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/sveltejs/kit/blob/03f1687fe612ce3d2d9131139b5b188d9cf90c64/packages/kit/src/utils/routing.js#L144-L180","documentation":"Param matchers convert the URL parameter string into a value for routing. After validation, `run_matcher` unwraps the validated result and requires the parsed value to be a string, number, boolean, or bigint, because these are the only types that can be meaningfully coerced into route params. Any other type (object, array, null, undefined) throws this error.","triggerScenarios":"A matcher's `~standard.validate` succeeds but returns a `value` that is an object, array, null, undefined, symbol, or function — e.g. a matcher that parses the param into a Date or a custom object and returns it.","commonSituations":"Custom matchers using Zod/Valibot schemas that `.transform()` the string into an object (like `z.coerce.date()`); returning undefined on success by mistake; a validator that passes through unknown input types unchanged.","solutions":["Change the matcher so the validated value is a primitive — parse objects in the route load instead","Use `.transform(String)` or return the raw string when you need structured data downstream","Add an explicit coercion step in the matcher so success values are string/number/boolean/bigint"],"exampleFix":"// before\nconst date = v.pipe(v.string(), v.transform((s) => new Date(s))); // returns object\n// after\nconst date = v.pipe(v.string(), v.regex(/^\\d{4}-\\d{2}-\\d{2}$/)); // keep as string, construct Date in +page.server.ts","handlingStrategy":"type-guard","validationCode":"const r = matcher['~standard'].validate('probe');\nif (!r.issues && !['string', 'number', 'boolean', 'bigint'].includes(typeof r.value)) {\n\tthrow new Error('Matcher success value must be a primitive');\n}","typeGuard":"function returnsPrimitive(matcher) {\n\tconst r = matcher['~standard'].validate('probe');\n\treturn r.issues ? false : ['string', 'number', 'boolean', 'bigint'].includes(typeof r.value);\n}","tryCatchPattern":"try {\n\tconst outcome = runMatcher(matcher, value);\n} catch (e) {\n\tif (e.message.startsWith('Param matcher must return')) {\n\t\t// fix matcher to return string/number/boolean/bigint\n\t}\n\tthrow e;\n}","preventionTips":["Avoid .transform() to non-primitives (Date, objects) in matcher schemas","Parse structured data in route load functions instead of in the matcher","Add a unit test asserting matcher output typeof is a primitive"],"tags":["params","matcher","standard-schema","type-conversion"],"backgroundTag":"invalid-matcher-return-type","analyzedSha":"03f1687fe612ce3d2d9131139b5b188d9cf90c64","analyzedAt":"2026-09-02T02:01:50.504Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}