sveltejs/kit · error

The "${lookup.get(key)}" and "${route.id}" routes conflict w

Error message

The "${lookup.get(key)}" and "${route.id}" routes conflict with each other

What it means

Two routes in src/routes normalize to the same URL pattern (same permutation of segments after removing duplicate slashes and trailing slashes). SvelteKit cannot decide which route handles that URL, so manifest creation fails at dev start or build.

Source

Thrown at packages/kit/src/core/sync/create_manifest_data/conflict.js:45

					a.push(b + next);
					if (!(matcher === '*' && b.endsWith('//'))) a.push(b + `<${matcher}>${next}`);
					return a;
				}, /** @type {string[]} */ ([]));
			}
		} else {
			permutations = [normalized];
		}

		for (const permutation of permutations) {
			// remove leading/trailing/duplicated slashes caused by prior
			// manipulation of optional parameters and (groups)
			const key = permutation
				.replace(/\/{2,}/, '/')
				.replace(/^\//, '')
				.replace(/\/$/, '');

			if (lookup.has(key)) {
				throw new Error(
					`The "${lookup.get(key)}" and "${route.id}" routes conflict with each other`
				);
			}

			lookup.set(key, route.id);
		}
	}
}

/** @param {string} id */
function normalize_route_id(id) {
	return (
		id
			// remove groups
			.replace(/(?<=^|\/)\(.+?\)(?=$|\/)/g, '')

			.replace(/\[[ux]\+([0-9a-f]+)\]/g, (_, x) =>
				String.fromCodePoint(parseInt(x, 16)).replace(/\//g, '%2f')

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Read both conflicting route ids from the error and delete or rename one
  2. Differentiate the patterns, e.g. add a literal prefix segment to one route
  3. Replace optional parameters with explicit routes or a single catch-all `[...slug]` with logic
  4. Check route groups — moving files between (groups) changes nothing about matching, so the duplicate remains

Example fix

// before — both match /x/about
// src/routes/[category]/about/+page.svelte
// src/routes/about/[page]/+page.svelte

// after
// src/routes/category/[name]/about/+page.svelte  (add literal 'category' segment)
Defensive patterns

Strategy: validation

Validate before calling

// before starting dev/build, list route dirs and flag normalized duplicates
import { readdirSync } from 'node:fs';
const segs = readdirSync('src/routes', { recursive: true }).filter((p) => p.endsWith('+page.svelte'));
const seen = new Map();
for (const s of segs) {
  const key = s.replace(/\/+page\.svelte/, '').replace(/\/+$/, '');
  if (seen.has(key)) console.warn('Conflict:', seen.get(key), 'vs', s);
  seen.set(key, s);
}

Try / catch

try {
  const manifest = await createManifestData(config);
} catch (e) {
  if (String(e.message).includes('routes conflict with each other')) {
    console.error('Rename one of the two conflicting routes listed in the message');
  }
  throw e;
}

Prevention

When it happens

Trigger: Creating e.g. `src/routes/about/[page]` and `src/routes/[category]/about` that produce identical path permutations; duplicate optional-param routes like `/[[x]]` and a static `/` route both matching the same key.

Common situations: Refactoring route names and leaving an old duplicate; route groups (`(group)`) accidentally flattening two routes to the same path; optional parameters colliding with static siblings.

Related errors


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