remix-run/react-router · error · Error

React Router presets must have a `name` property defined.

Error message

React Router presets must have a `name` property defined.

What it means

Thrown during React Router config resolution when iterating reactRouterUserConfig.presets and a preset object lacks a name property (preset.name is falsy). Presets are an array in react-router.config.ts; each must declare a name for identification and deduplication. The check runs after the user config is loaded, validated, and deep-frozen, so it fires during build/dev startup before the preset's reactRouterConfig callback is invoked.

Source

Thrown at packages/react-router-dev/config/config.ts:494

      if (validateConfig) {
        const error = validateConfig(reactRouterUserConfig);
        if (error) {
          return err(error);
        }
      }
    } catch (error) {
      return err(`Error loading ${reactRouterConfigFile}: ${error}`);
    }
  }

  // Prevent mutations to the user config
  reactRouterUserConfig = deepFreeze(cloneDeep(reactRouterUserConfig));

  let presets: ReactRouterConfig[] = (
    await Promise.all(
      (reactRouterUserConfig.presets ?? []).map(async (preset) => {
        if (!preset.name) {
          throw new Error(
            "React Router presets must have a `name` property defined.",
          );
        }

        if (!preset.reactRouterConfig) {
          return null;
        }

        let configPreset: ReactRouterConfig = omit(
          await preset.reactRouterConfig({ reactRouterUserConfig }),
          excludedConfigPresetKeys,
        );

        return configPreset;
      }),
    )
  ).filter(function isNotNull<T>(value: T | null): value is T {
    return value !== null;

View on GitHub (pinned to 1fd704a7da)

Solutions

  1. Add a unique name string to every preset in react-router.config.ts: presets: [{ name: 'my-preset', reactRouterConfig: () => ({...}) }].
  2. If importing a preset from a package, ensure its exported object includes name, or wrap it: { name: 'pkg', ...importedPreset }.
  3. Remove the offending preset if it is unused.
  4. Lint your config by logging presets.map(p => p.name) before build to catch missing names early.

Example fix

// before (react-router.config.ts)
export default {
  presets: [{ reactRouterConfig: () => ({ ssr: true }) }],
} satisfies ReactRouterConfig;
// after
export default {
  presets: [{ name: 'ssr-preset', reactRouterConfig: () => ({ ssr: true }) }],
} satisfies ReactRouterConfig;
Defensive patterns

Strategy: validation

Validate before calling

// Validate presets before build/dev
function presetsAreNamed(presets: any[]): boolean {
  return Array.isArray(presets) && presets.every((p) => typeof p?.name === 'string' && p.name.length > 0);
}
const cfg = (await import('./react-router.config.ts')).default;
if (!presetsAreNamed(cfg.presets ?? [])) {
  throw new Error('Every preset must define a unique `name`.');
}

Type guard

interface ReactRouterPreset { name: string; reactRouterConfig?: (ctx: any) => any | Promise<any>; }
function isNamedPreset(p: unknown): p is ReactRouterPreset {
  return typeof p === 'object' && p !== null && typeof (p as any).name === 'string' && (p as any).name.length > 0;
}

Prevention

When it happens

Trigger: Authoring react-router.config.ts with presets: [{ reactRouterConfig: () => ({...}) }] (name omitted); spreading an object that drops name; a preset factory returning an object without name; importing a preset from a package whose default export is unnamed.

Common situations: Converting a flat config into presets and forgetting the name field; copy-pasting a preset example that omitted name; upgrading a preset package whose API changed to require name; community preset without a name.

Related errors


AI-assisted analysis of remix-run/react-router@1fd704a7da (2026-08-12). Data as JSON: /api/errors/f64d40a1a05d8124. Report an issue: GitHub.