diff --git a/.changeset/tender-snails-attack.md b/.changeset/tender-snails-attack.md new file mode 100644 index 0000000000..c1f9d8f756 --- /dev/null +++ b/.changeset/tender-snails-attack.md @@ -0,0 +1,5 @@ +--- +"@react-router/dev": patch +--- + +Add validation for a route's id not being 'root' diff --git a/packages/react-router-dev/__tests__/route-config-test.ts b/packages/react-router-dev/__tests__/route-config-test.ts index 0fc700d7fa..de788448ac 100644 --- a/packages/react-router-dev/__tests__/route-config-test.ts +++ b/packages/react-router-dev/__tests__/route-config-test.ts @@ -76,6 +76,21 @@ describe("route config", () => { `); }); + it("is invalid it uses the 'root' id", () => { + let result = validateRouteConfig({ + routeConfigFile: "routes.ts", + routeConfig: [route("/", "root.tsx", { id: "root" })], + }); + + expect(result.valid).toBe(false); + expect(!result.valid && result.message).toMatchInlineSnapshot(` + "Route config in "routes.ts" is invalid. + + Path: routes.0.id + A route cannot use the reserved id 'root'." + `); + }); + it("is invalid when property is wrong type", () => { let result = validateRouteConfig({ routeConfigFile: "routes.ts", diff --git a/packages/react-router-dev/config/routes.ts b/packages/react-router-dev/config/routes.ts index ef384788e6..03a2a4d898 100644 --- a/packages/react-router-dev/config/routes.ts +++ b/packages/react-router-dev/config/routes.ts @@ -112,7 +112,12 @@ export const routeConfigEntrySchema: v.BaseSchema< ); }, "Invalid type: Expected object but received a promise. Did you forget to await?"), v.object({ - id: v.optional(v.string()), + id: v.optional( + v.pipe( + v.string(), + v.notValue("root", "A route cannot use the reserved id 'root'.") + ) + ), path: v.optional(v.string()), index: v.optional(v.boolean()), caseSensitive: v.optional(v.boolean()),