Register-routes.js Error on V3 to V4 Migration

System Information
  • Strapi Version: 4.3.2
  • Operating System: OSX
  • Database: SQLITE3 & MYSQL
  • Node Version: 16.16.0
  • NPM Version: 8.11.0
  • Yarn Version: 1.22.19

I am migrating my app from V3 to V4, I’ve updated the configs, ran codemods, updated routers, controllers, services.

Before I run any DB upgrades, I’m trying to “yarn develop” but I keep getting stuck with this error:

[2022-07-22 10:33:39.836] debug: ⛔️ Server wasn't able to start properly.
[2022-07-22 10:33:39.838] error: Cannot read properties of undefined (reading 'forEach')
TypeError: Cannot read properties of undefined (reading 'forEach')
@strapi/strapi/lib/services/server/register-routes.js:98:21
/node_modules/lodash/lodash.js:4967:15

If I turn on DB_DEBUG, I can see that this is always caused at this point:

{
  method: 'select',
  options: {},
  timeout: false,
  cancelOnTimeout: false,
  bindings: [],
  __knexQueryUid: 'tXmm9qcsZWuuFrkjDSrjD',
  sql: 'select `t0`.* from `strapi_webhooks` as `t0`'
}

I’ve tried both new MYSQL and SQLITE but to no avail, Please Help

I’ve realised my error and the problem has been sorted out

I had a copy of the old router in the same routes folder with the postfix “.old”, seems like that was getting picked up by Strapi and causing it to crash.

Sample of the problem in the SS attached.

I have installed the new strapi v4 typescript and getting the same issue.
However it is a new project altogether and there is nothing yet added.

The strapi server starts for the first time.
Then I created the admin account.
Directed to admin dashboard.
And after adding a content-type , when clicked on save it will fail to restart strapi.
Getting the same error cannot read properties of undefined (reading 'forEach')

Points to be Noted:

  • This works smoothly on local machine (Windows 11)
  • Gives issues on local machine (Windows 11) when using inside mono_repo
  • If I modify the file “mono_repo_root_folder/strapi/node_modules/@strapi/strapi/lib/services/server/register-routes.js” ,
    in method const registerAPIRoutes = (strapi) => { … }, add a ‘?’ to router.routes.forEach((route) => {…} thereby converting it to router.routes?.forEach((route) => {…} then the entire flow starts working properly.

Sample of the SS of file in node_modules attached where i added my modification:

However this is just a temporary fix for running on local and not a proper solution.
Also there is a TODO note inside this node_modules file.
Please let me know if you know anything about this, or can redirect to any link/page/forum etc.
It will be a great help, as rest of my plans are already in motion regarding implementation and deployment.
Stuck on this since couple of weeks. may have to switch to different cms if no solution is found.

As was the case with me, this is usually caused by extra route files in the routes folder, can you please double check that you don’t have any extra files in the routes folder?

Thankyou. I will try out your suggestion and update on the same

@zackmorris Checked for extra routes. nothing of the sort exists.
Retried setup from scratch on Ubuntu, in monorepo and all is working fine at the moment. Probably it has some issues when initializing from Windows. Will update if I come across more info about it.

Update:
no issue found.
maybe a patch update or something was added, after which the error for routes resolved itself
current version: “@strapi/strapi”: “4.5.4”
Working smmothly on Ubuntu | Mac | Windows :slight_smile:
cc @zackmorris

Hi Rohit, i’m doing like you told but still have error like that. What are the changes of register-routes after you downgrade version? @Rohit_Meshram

@nhat
here are my current stats:

nvm version: 1.1.10
node version: v16.13.0

package.json

{...
  "dependencies": {
    "@strapi/plugin-i18n": "4.5.4",
    "@strapi/plugin-users-permissions": "4.5.4",
    "@strapi/strapi": "4.5.4",
    "aws-sdk": "^2.1286.0",
    "pg": "^8.8.0",
    "sharp": "0.28.3"
  },
  "strapi": {
    "uuid": "******************************"
  },
  "engines": {
    "node": ">=14.19.1 <=18.x.x",
    "npm": ">=6.0.0"
  },
...
}

and this is the default register-routes.js in the mentioned node-modules

'use strict';

const _ = require('lodash');

const createRouteScopeGenerator = (namespace) => (route) => {
  const prefix = namespace.endsWith('::') ? namespace : `${namespace}.`;

  if (typeof route.handler === 'string') {
    _.defaultsDeep(route, {
      config: {
        auth: {
          scope: [`${route.handler.startsWith(prefix) ? '' : prefix}${route.handler}`],
        },
      },
    });
  }
};

/**
 * Register all routes
 * @param {import('../../').Strapi} strapi
 */
module.exports = (strapi) => {
  registerAdminRoutes(strapi);
  registerAPIRoutes(strapi);
  registerPluginRoutes(strapi);
};

/**
 * Register admin routes
 * @param {import('../../').Strapi} strapi
 */
const registerAdminRoutes = (strapi) => {
  const generateRouteScope = createRouteScopeGenerator(`admin::`);

  strapi.admin.routes.forEach((route) => {
    generateRouteScope(route);
    route.info = { pluginName: 'admin' };
  });

  strapi.server.routes({
    type: 'admin',
    prefix: '/admin',
    routes: strapi.admin.routes,
  });
};

/**
 * Register plugin routes
 * @param {import('../../').Strapi} strapi
 */
const registerPluginRoutes = (strapi) => {
  for (const pluginName of Object.keys(strapi.plugins)) {
    const plugin = strapi.plugins[pluginName];

    const generateRouteScope = createRouteScopeGenerator(`plugin::${pluginName}`);

    if (Array.isArray(plugin.routes)) {
      plugin.routes.forEach((route) => {
        generateRouteScope(route);
        route.info = { pluginName };
      });

      strapi.server.routes({
        type: 'admin',
        prefix: `/${pluginName}`,
        routes: plugin.routes,
      });
    } else {
      _.forEach(plugin.routes, (router) => {
        router.type = router.type || 'admin';
        router.prefix = `/${pluginName}`;
        router.routes.forEach((route) => {
          generateRouteScope(route);
          route.info = { pluginName };
        });

        strapi.server.routes(router);
      });
    }
  }
};

/**
 * Register api routes
 * @param {import('../../').Strapi} strapi
 */
const registerAPIRoutes = (strapi) => {
  for (const apiName of Object.keys(strapi.api)) {
    const api = strapi.api[apiName];

    const generateRouteScope = createRouteScopeGenerator(`api::${apiName}`);

    _.forEach(api.routes, (router) => {
      // TODO: remove once auth setup
      // pass meta down to compose endpoint
      router.type = 'content-api';
      router.routes.forEach((route) => {
        generateRouteScope(route);
        route.info = { apiName };
      });

      return strapi.server.routes(router);
    });
  }
};