✨ Strapi MCP is now Generally Available - let your agents manage your Strapi content ✨

EcosystemIntermediate5 min read

Fixing TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string in Strapi

September 9, 2026
Fixing TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string in Strapi

You create a component in the Content-Type Builder, hit save, and the admin panel hangs on "The restart is taking longer than expected". The terminal shows:

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
    at Object.join (node:path:433:7)
    at .../node_modules/@strapi/strapi/dist/core/loaders/components.js:17:31
    at Array.forEach (<anonymous>)
    at Object.loadComponents (...)
    at async Strapi.loadComponents (...)

Delete the component's .json file and Strapi boots again. Recreate it and it breaks again.

What the stack trace is telling you

The frame that matters is core/loaders/components.js. Strapi is walking src/components/, and for each entry it builds a file path with path.join(...). One of the arguments it passes is undefined, so Node throws before Strapi can produce a friendlier message.

In other words: Strapi found something in your components directory it could not interpret. Either the directory layout is wrong, a schema file is malformed, or, historically, the loader itself had a platform-specific bug.

Cause 1: The known Windows bug in Strapi 4.25.x

If you are on Windows and this started when you created a component, you are probably hitting a regression in the component loader that shipped in Strapi 4.25.x. It was reported on GitHub as "Windows only: Server crashes when creating a Component", and it did not reproduce on macOS or Linux, which is why teams saw it on developer laptops but never in CI or production.

Fix: upgrade. The bug was fixed in later releases, and if you are still on 4.x you should be planning the move to Strapi 5 regardless.

npx @strapi/upgrade latest

Downgrading to an older 4.x, which some forum replies suggest, works as an emergency unblock and leaves you further from a supported version. Prefer upgrading.

Cause 2: The component directory layout is wrong

Every component must live two levels deep: src/components/<category>/<component>.json.

src/components/
├── shared/
│   ├── seo.json
│   └── meta-social.json
└── layout/
    └── hero.json

The loader iterates categories first, then files inside them. A .json file placed directly in src/components/ has no category, and the loader ends up joining undefined.

src/components/
└── seo.json          ← wrong: no category folder

This happens when a component file is moved by hand, when a merge resolves badly, or when a file is copied from another project. Check for it:

find src/components -maxdepth 1 -name "*.json"
# Any output here is a misplaced component

Also look for stray non-JSON files: an editor backup (hero.json~), a .DS_Store, or an orig file left by a merge conflict will confuse the loader.

find src/components -type f ! -name "*.json"

Cause 3: The schema JSON is malformed

A component schema needs collectionName, info, and attributes. Missing collectionName is the one that produces path errors, because it is used to derive the table name and the loader assumes it is present.

{
  "collectionName": "components_shared_seos",
  "info": {
    "displayName": "seo",
    "icon": "search",
    "description": ""
  },
  "options": {},
  "attributes": {
    "metaTitle": {
      "type": "string",
      "required": true,
      "maxLength": 60
    },
    "metaDescription": {
      "type": "text",
      "maxLength": 160
    },
    "metaImage": {
      "type": "media",
      "multiple": false,
      "allowedTypes": ["images"]
    }
  }
}

Validate every component file at once:

for f in src/components/*/*.json; do
  node -e "
    const s = require('./$f');
    const missing = ['collectionName','info','attributes'].filter(k => !s[k]);
    if (missing.length) console.log('$f missing:', missing.join(', '));
  " 2>&1 | grep -v '^$'
done

Anything that prints is a candidate.

Also check plain JSON validity, such as a trailing comma or an unclosed brace after a hand edit:

for f in src/components/*/*.json; do
  node -e "JSON.parse(require('fs').readFileSync('$f','utf8'))" || echo "INVALID: $f"
done

Cause 4: A content type references a component that no longer exists

If a content type's schema.json has:

"seo": {
  "type": "component",
  "repeatable": false,
  "component": "shared.seo"
}

…and src/components/shared/seo.json was deleted, the loader tries to resolve a component that is not there. Depending on where it fails you get this error or the closely related Cannot read properties of undefined (reading 'attributes').

Find every referenced component and check each one exists:

grep -rho '"component": "[^"]*"' src/api src/components \
  | sed 's/.*: "//; s/"//' | sort -u \
  | while read c; do
      f="src/components/${c/./\/}.json"
      [ -f "$f" ] || echo "MISSING: $c (expected $f)"
    done

Cause 5: A stale build or cache

If you fixed the schema and the error persists, you may be loading a stale compiled copy:

rm -rf dist .cache build .strapi
npm run build
npm run develop

On a TypeScript project the compiled dist/ retains old component definitions until rebuilt, so a deleted component can linger there and keep crashing the loader.

Recovering from a boot loop

When Strapi will not start at all, you cannot use the admin panel to undo the change. Work on the filesystem:

  1. Find the most recent change. git status and git diff usually show it immediately: a new file in src/components/ or a modified schema.json.
  2. Move it out of the tree rather than deleting it, so you keep the content: mv src/components/shared/seo.json /tmp/.
  3. Start Strapi. If it boots, that file was the problem.
  4. Fix and reinstate it, or recreate it through the Content-Type Builder now that you are running again.

If you removed a component that content types still reference, you will need to remove those references from the relevant schema.json files too, or you trade one boot error for another.

Preventing it

  • Commit src/components/ and src/api/*/content-types/. These are code. Reviewing a schema diff catches most of this before it reaches anyone else.
  • Create components through the Content-Type Builder rather than by hand. It writes a valid collectionName and a valid category path.
  • Boot Strapi in CI. A job that runs npm run build and starts the server against a throwaway database catches broken schemas at pull-request time rather than on someone's machine.
  • Stay current. This particular crash was a bug that got fixed. Running a supported version means you inherit those fixes.

Further reading

Theodore Kelechukwu OnyejiakuDevRel and Community | Software Developer | Technical Writer

Theodore is a Technical Writer and a full-stack software developer. He loves writing technical articles, building solutions, and sharing his expertise.

Seeding Data in Strapi: Why Migrations are the Wrong Tool
EcosystemIntermediate·7 min read

Seeding Data in Strapi: Why Migrations are the Wrong Tool

Migrations run before Strapi's schema sync, so seeding a brand-new content type fails on the missing table. Use bootstrap instead, idempotently.

·September 9, 2026
Strapi and TypeScript: compiling when there are type errors
EcosystemAdvanced·6 min read

Strapi and TypeScript: compiling when there are type errors

A single type error stops your Strapi dev server. The tsconfig settings that let it build anyway, and when each one is actually appropriate.

·September 9, 2026
"Cannot read properties of undefined (reading 'attributes')" in Strapi
EcosystemIntermediate·6 min read

"Cannot read properties of undefined (reading 'attributes')" in Strapi

Strapi will not boot because a content type references a component or relation that does not exist. How to find the broken reference quickly.

·September 9, 2026