sveltejs/kit · error · Error

Param matcher must return a string, number, boolean, or…

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.

Solutions

  1. Change the matcher so the validated value is a primitive — parse objects in the route load instead
  2. Use `.transform(String)` or return the raw string when you need structured data downstream
  3. 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

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


AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02). Data as JSON: /api/errors/1aca054ce1bf0945. Report an issue: GitHub.

Appendix: 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)