sveltejs/kit · error · Error

Async param matchers are not supported

Error message

Async param matchers are not supported

What it means

Param matchers in SvelteKit use the Standard Schema `validate` API. `run_matcher` requires validation to be synchronous; if a matcher's `~standard.validate` returns a Promise (async validation), routing cannot proceed because param matching happens synchronously during route resolution. The library therefore rejects async matchers outright.

Source

Thrown at packages/kit/src/utils/routing.js:147

 * don't affect the path (i.e. groups). The root route is represented by `/`
 * and will be returned as `['']`.
 * @param {string} route
 * @returns string[]
 */
export function get_route_segments(route) {
	return route.slice(1).split('/').filter(affects_path);
}

/**
 * @param {ParamMatcher} matcher
 * @param {string} value
 * @returns {{ success: true, value: any } | { success: false }}
 */
function run_matcher(matcher, value) {
	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 };

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Rewrite the matcher's `validate` so it returns the result synchronously (no `async`, no awaited refinements)
  2. Move any async work (e.g. DB lookups) out of the matcher into the route's load function and validate there
  3. Use a sync-only schema API for the matcher (e.g. Valibot sync parsers, Zod `.safeParse` instead of async paths)

Example fix

// before
const matcher = defineMatcher({
	'~standard': {
		async validate(value) {
			return (await existsInDb(value)) ? { value } : { issues: [{ message: 'nope' }] };
		}
	}
});
// after
const matcher = defineMatcher({
	'~standard': {
		validate(value) {
			return /^[a-z0-9-]+$/.test(value) ? { value } : { issues: [{ message: 'invalid' }] };
		}
	}
});
Defensive patterns

Strategy: try-catch

Validate before calling

const result = matcher['~standard'].validate('test-value');
if (result instanceof Promise) {
	throw new Error('Matcher must be synchronous');
}

Type guard

function isSyncMatcher(matcher) {
	const r = matcher['~standard'].validate('probe');
	return !(r instanceof Promise);
}

Try / catch

try {
	const outcome = runMatcher(matcher, value);
} catch (e) {
	if (e.message === 'Async param matchers are not supported') {
		// replace matcher with a synchronous schema
	}
	throw e;
}

Prevention

When it happens

Trigger: A matcher defined with `defineParams` uses an async Standard Schema implementation, or `run_matcher` is called with a matcher whose `validate(value)` returns a Promise instead of a plain result object.

Common situations: Writing a custom Standard Schema adapter with an `async validate()` method; using a schema library configured in async mode (e.g. async refinements/transforms in Valibot/Zod async APIs) for param matchers; upgrading a schema library so a previously sync validator became async.

Related errors


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