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

EcosystemIntermediate●5 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.

The True TCO of Self-Hosting a Headless CMS
Ecosystem·12 min read

The True TCO of Self-Hosting a Headless CMS

Discover the real cost of self-hosting Strapi 5: infrastructure, DevOps labor, security, migrations, and hidden costs—with a practical TCO checklist.

·September 24, 2026
How Do You Preserve SEO Rankings During a CMS Migration?
Ecosystem·13 min read

How Do You Preserve SEO Rankings During a CMS Migration?

A developer's CMS migration SEO checklist: URL mapping, 301 redirects, on-page parity, robots.txt, redirect testing, and post-launch monitoring.

·September 24, 2026
What Is a Content Agent? Agentic AI for CMS Workflows Explained
Ecosystem·24 min read

What Is a Content Agent? Agentic AI for CMS Workflows Explained

Learn what a content agent is, how the observe-plan-act-evaluate loop works, and when agentic AI makes sense for your CMS workflows and content operations.

·September 24, 2026