remix-run/remix · error · Error
Detected a route map cycle at "${currentPath}" via "${existi
Error message
Detected a route map cycle at "${currentPath}" via "${existingPath}". What it means
The routes map is traversed recursively with a `seen` map; if the same object reference is reached twice, your config contains a cycle (direct or indirect self-reference) and the worker aborts instead of infinite-looping.
Source
Thrown at packages/cli/src/lib/load-route-map-worker.ts:49
}
return normalizeRouteGroup(routeModule.routes, [], new Map())
}
function normalizeRouteGroup(
value: unknown,
parentSegments: string[],
seen: Map<object, string>,
): RawRouteTreeNode[] {
if (!isPlainObject(value)) {
let location = parentSegments.length === 0 ? 'routes' : parentSegments.join('.')
throw new Error(`Invalid route map value at "${location}". Expected a nested route object.`)
}
let existingPath = seen.get(value)
let currentPath = parentSegments.length === 0 ? 'routes' : parentSegments.join('.')
if (existingPath != null) {
throw new Error(`Detected a route map cycle at "${currentPath}" via "${existingPath}".`)
}
seen.set(value, currentPath)
try {
return Object.entries(value).map(([key, entryValue]) => {
let nameSegments = [...parentSegments, key]
let name = nameSegments.join('.')
let routeLeaf = readRouteLeaf(entryValue)
if (routeLeaf !== undefined) {
return {
children: [],
key,
kind: 'route',
method: routeLeaf.method,
name,
pattern: routeLeaf.pattern,View on GitHub (pinned to 9696913134)
Solutions
- Find the reported path (e.g. 'routes.admin') and remove the self/indirect reference
- If reusing a subtree, clone it with structuredClone or spread (`{ ...shared }`) instead of referencing the same object
- Avoid `obj.child = obj` patterns when assembling groups programmatically
Example fix
// before
let admin = {}; admin.self = admin
export let routes = { admin }
// after
export let routes = { admin: {} } Defensive patterns
Strategy: validation
Validate before calling
function assertAcyclic(node, seen = new Set()) {
if (seen.has(node)) throw new Error('cycle')
seen.add(node)
for (let k in node) if (typeof node[k] === 'object') assertAcyclic(node[k], seen)
seen.delete(node)
} Prevention
- Clone shared subtrees with spread or structuredClone
- Never assign a parent object into its own descendants
- Prefer static literal route maps over programmatic assembly
When it happens
Trigger: An object in the routes map referencing itself: `let group = { nested: group }` or two objects referencing each other via getter/spread chains that preserve identity.
Common situations: Building route groups programmatically with variables and accidentally assigning a parent into its own children; using shared constant objects that get inserted at multiple nesting levels via assignment (fine with spread, a cycle with direct reference).
Related errors
- mounts values must be relative to rootDir. Received "${fileR
- mounts keys must be URL pathnames without query strings, fra
- mounts values must not overlap. Received "${mount.fileRootVa
- mounts keys must not overlap. Received "${mount.urlRootKey}"
- Route module ${routesFile} must export a named "routes" valu
AI-assisted analysis of remix-run/remix@9696913134 (2026-08-27).
Data as JSON: /api/errors/603aa8017793ca71.
Report an issue: GitHub.