sveltejs/kit · error · Error
Param matcher must return a string, number, boolean, or bigi
Error message
Param matcher must return a string, number, boolean, or bigint
What it means
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.
Source
Thrown at packages/kit/src/utils/routing.js:162
const result = matcher['~standard'].validate(value);
if (result instanceof Promise) {
throw new Error('Async param matchers are not supported');
}
if (result.issues) {
return { success: false };
}
const parsed = result.value;
if (
typeof parsed !== 'string' &&
typeof parsed !== 'number' &&
typeof parsed !== 'boolean' &&
typeof parsed !== 'bigint'
) {
throw new Error('Param matcher must return a string, number, boolean, or bigint');
}
return { success: true, value: parsed };
}
/**
* @param {RegExpMatchArray} match
* @param {import('types').RouteParam[]} params
* @param {Record<string, ParamMatcher>} matchers
*/
export function exec(match, params, matchers) {
/** @type {Record<string, any>} */
const result = {};
const values = match.slice(1);
const values_needing_match = values.filter((value) => value !== undefined);
let buffered = 0;View on GitHub (pinned to 03f1687fe6)
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
Example fix
// before
const date = v.pipe(v.string(), v.transform((s) => new Date(s))); // returns object
// after
const date = v.pipe(v.string(), v.regex(/^\d{4}-\d{2}-\d{2}$/)); // keep as string, construct Date in +page.server.ts Defensive patterns
Strategy: type-guard
Validate before calling
const r = matcher['~standard'].validate('probe');
if (!r.issues && !['string', 'number', 'boolean', 'bigint'].includes(typeof r.value)) {
throw new Error('Matcher success value must be a primitive');
} Type guard
function returnsPrimitive(matcher) {
const r = matcher['~standard'].validate('probe');
return r.issues ? false : ['string', 'number', 'boolean', 'bigint'].includes(typeof r.value);
} Try / catch
try {
const outcome = runMatcher(matcher, value);
} catch (e) {
if (e.message.startsWith('Param matcher must return')) {
// fix matcher to return string/number/boolean/bigint
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Async param matchers are not supported
- Parameter values must be a string, number, boolean, or bigin
- Invalid param definition
- ${manifest_data.params} does not export `params` from `defin
- Missing params for dynamic route ID ${id}
AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02).
Data as JSON: /api/errors/1aca054ce1bf0945.
Report an issue: GitHub.