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

While resolving react-router.config.ts, every entry of the presets array must have a name property (presets are identified by name when merged and reported). During config resolution the loader maps over presets and throws on the first entry lacking name, which fails the dev server or build startup.

Solutions

  1. Add a name to every entry in the presets array
  2. Scan the array for accidental empty objects or stray trailing entries
  3. Restart the dev server after saving react-router.config.ts

Example fix

// before: react-router.config.ts
export default {
  presets: [
    { reactRouterConfig: async () => ({ ssr: true }) },
  ],
};

// after
export default {
  presets: [
    {
      name: "ssr-on",
      reactRouterConfig: async () => ({ ssr: true }),
    },
  ],
};
Defensive patterns

Strategy: type-guard

Validate before calling

import type { Preset, ReactRouterConfig } from "@react-router/dev";

function isNamedPreset(p: Preset): p is Preset & { name: string } {
  return typeof p.name === "string" && p.name.length > 0;
}

export default {
  presets: myPresets.every(isNamedPreset) ? myPresets : (() => {
    throw new Error("Every preset needs a non-empty `name`");
  })(),
} satisfies ReactRouterConfig;

Type guard

interface PresetLike {
  name?: unknown;
  reactRouterConfig?: unknown;
}

function isNamedPreset(p: PresetLike): p is { name: string } & PresetLike {
  return typeof p.name === "string" && p.name.length > 0;
}

Prevention

When it happens

Trigger: Writing presets: [{}] (empty object), or presets: [{ reactRouterConfig: ... }] with the config function but no name; JS configs or `any` casts bypassing the TypeScript Preset type that would normally flag it.

Common situations: Adding a first preset to react-router.config.ts; copy-pasting preset examples that omit name; refactors that rename or drop the name field.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: 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 6beaca3952)