facebook/docusaurus · error · Error
Route ${route.path} has conflicting props declared using bot
Error message
Route ${route.path} has conflicting props declared using both route.modules and route.props APIs for keys: ${conflictingPropNames.join(', ')}\nThis is not permitted, otherwise one prop would override the over. What it means
Thrown by `ensureNoPropsConflict(route)` when the same prop key is declared both in `route.props` and `route.modules`. These two APIs feed the same prop namespace on the rendered component, so a duplicate key would silently overwrite one value; Docusaurus rejects it up front. (Note: the message has a known typo — 'override the over' — but the meaning is clear.)
Source
Thrown at packages/docusaurus/src/server/codegen/codegenRoutes.ts:413
generateRoutePropFilename(route),
);
const modulePath = path.posix.join(generatedFilesDir, relativePath);
const aliasedPath = path.posix.join('@generated', relativePath);
await generate(generatedFilesDir, modulePath, moduleContent);
return aliasedPath;
}
function ensureNoPropsConflict(route: RouteConfig) {
if (!route.props && !route.modules) {
return;
}
const conflictingPropNames = _.intersection(
Object.keys(route.props ?? {}),
Object.keys(route.modules ?? {}),
);
if (conflictingPropNames.length > 0) {
throw new Error(
`Route ${
route.path
} has conflicting props declared using both route.modules and route.props APIs for keys: ${conflictingPropNames.join(
', ',
)}\nThis is not permitted, otherwise one prop would override the over.`,
);
}
}
async function preprocessRouteProps({
generatedFilesDir,
route,
plugin,
}: {
generatedFilesDir: string;
route: RouteConfig;
plugin: PluginIdentifier;
}): Promise<RouteConfig> {View on GitHub (pinned to 3f483e80e3)
Solutions
- Inspect the conflicting key names in the error message and remove the duplicate from either `props` or `modules`.
- Prefer `modules` for code-split lazy-loaded values and `props` for inline serializable values — keep the same key in only one.
- Rename one of the colliding keys if both are genuinely needed.
- Add a small assertion in your plugin's route builder to catch this in dev: `_.intersection(Object.keys(route.props??{}), Object.keys(route.modules??{})).length === 0`.
Example fix
// before
export default {
path: '/x',
component: '@theme/Page',
props: { data: 1 },
modules: { data: '@generated/data.js' }, // conflicts
};
// after
export default {
path: '/x',
component: '@theme/Page',
modules: { data: '@generated/data.js' },
}; Defensive patterns
Strategy: validation
Validate before calling
const conflict = _.intersection(Object.keys(route.props ?? {}), Object.keys(route.modules ?? {}));
if (conflict.length > 0) throw new Error(`Conflicting prop keys: ${conflict.join(', ')}`); Type guard
function hasNoPropsConflict(route: any): boolean {
const pk = Object.keys(route?.props ?? {});
const mk = Object.keys(route?.modules ?? {});
return pk.every((k) => !mk.includes(k));
} Prevention
- Pick one prop API (`props` or `modules`) per key — never both.
- Add a plugin-dev assertion using the type guard above.
- Code-review route configs from migrated plugins for leftover duplicate keys.
When it happens
Trigger: A plugin route (or a user-authored route via the routing API) declares `props: { foo: ... }` and `modules: { foo: ... }` for the same key `foo`.
Common situations: Plugin author migrates from `props` to `modules` (or vice-versa) and forgets to remove the old key; copy-paste between routes; merging two plugins' route configs that both inject the same prop name (e.g. `auth`, `data`).
Related errors
- Invalid route config: path must be a string and component is
- Duplicate permalinks found in tags file: ${duplicateList}
- Docusaurus couldn't generate a unique hash for route ${route
- Invalid command: ${command}
- Invalid package manager choice ${packageManager}. Must be on
AI-assisted analysis of facebook/docusaurus@3f483e80e3 (2026-08-12).
Data as JSON: /api/errors/338dfc83526d0156.
Report an issue: GitHub.