strapi/strapi · error · Error

Invalid route config ${error.message}

Error message

Invalid route config ${error.message}

What it means

validateRouteConfig runs each route through a yup schema requiring method (one of GET/POST/PUT/PATCH/DELETE/ALL), path (string), and a handler (string, array, or function). Optional request/response/config shapes are also constrained. On any yup ValidationError the original message is wrapped and rethrown, failing route registration — typically at server boot or plugin load.

Source

Thrown at packages/core/core/src/services/server/routing.ts:79

      middlewares: yup
        .array()
        // FIXME: fixed in yup v1
        .of(policyOrMiddlewareSchema as any)
        .notRequired(),
    })
    .notRequired(),
});

const validateRouteConfig = (routeConfig: Core.RouteInput) => {
  try {
    return routeSchema.validateSync(routeConfig, {
      strict: true,
      abortEarly: false,
      stripUnknown: true,
    });
  } catch (error) {
    if (error instanceof yup.ValidationError) {
      throw new Error(`Invalid route config ${error.message}`);
    }
  }
};

const createRouteManager = (strapi: Core.Strapi, opts: { type?: string } = {}) => {
  const { type } = opts;

  const composeEndpoint = createEndpointComposer(strapi);

  const createRoute = (route: Core.RouteInput, router: Router) => {
    validateRouteConfig(route);

    // NOTE: the router type is used to tag controller actions and for authentication / authorization so we need to pass this info down to the route level
    const routeWithInfo = Object.assign(route, {
      info: {
        ...route.info,
        type: type ?? 'api',
      },

View on GitHub (pinned to 4a4101264d)

Solutions

  1. Ensure method is uppercase and in [GET, POST, PUT, PATCH, DELETE, ALL].
  2. Provide a non-empty path string and a valid handler (string 'controller.action', array, or function).
  3. For config.auth use either false or { scope: ['read'] }.
  4. Read the embedded yup error.message in the thrown text for the specific failing field.

Example fix

// before (throws — lowercase method, missing handler)
module.exports = {
  routes: [
    { method: 'get', path: '/hello' },
  ],
};

// after
module.exports = {
  routes: [
    { method: 'GET', path: '/hello', handler: 'myController.find' },
  ],
};
Defensive patterns

Strategy: validation

Validate before calling

const METHODS = ['GET','POST','PUT','PATCH','DELETE','ALL'];
function validateRoute(r) {
  if (!METHODS.includes(r.method)) throw new Error('Invalid method');
  if (typeof r.path !== 'string' || !r.path) throw new Error('Invalid path');
  if (!(typeof r.handler === 'string' || Array.isArray(r.handler) || typeof r.handler === 'function')) {
    throw new Error('Invalid handler');
  }
}

Type guard

const isRouteInput = (r: unknown): boolean =>
  typeof r === 'object' && r !== null &&
  ['GET','POST','PUT','PATCH','DELETE','ALL'].includes((r as any).method) &&
  typeof (r as any).path === 'string';

Prevention

When it happens

Trigger: Registering a custom route with a missing or invalid method/path/handler, a method not in the allowed enum (e.g. 'OPTIONS'), or a config.auth value that is neither false nor { scope: string[] }.

Common situations: Plugin route typos; copy-pasting a route and forgetting the handler; setting config.auth to a truthy non-object; using a lowercase method ('get').

Related errors


AI-assisted analysis of strapi/strapi@4a4101264d (2026-08-12). Data as JSON: /api/errors/b7af47345126d9a1. Report an issue: GitHub.