Fixing 'Element type is invalid: expected a string but got: undefined' in React

beginner⚛️ React2026-05-25| React 16.x, 17.x, 18.x / Next.js / Vite / Webpack

Error Message

React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
#react#javascript#debugging#frontend

The Error Message

You’re staring at a blank screen, and the console is screaming in red text. It’s a rite of passage for every React developer. The error usually looks like this:

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.

What Your Browser Is Actually Saying

React is essentially telling you: "You asked me to render something, but I have no idea what it is." When you write <MyComponent />, React evaluates that variable. If it’s undefined, the rendering engine crashes. React only understands HTML tags (like 'div' or 'span') or actual JavaScript functions and classes.

This breakdown almost always happens because your import and export statements are out of sync. One file is sending a package, but the other isn't receiving it correctly.

1. The 90% Culprit: Default vs. Named Imports

I see this mistake constantly during fast-paced refactoring. If your component is exported as default, you cannot use curly braces to import it. If it’s a named export, you must use them.

Scenario A: The Default Export Trap

If you use export default, you’re sending the whole file as one unit.

Wrong:

// MyComponent.js
export default function MyComponent() { return <div>Hello</div>; }

// App.js
import { MyComponent } from './MyComponent'; // Error! MyComponent is undefined here.

Right:

import MyComponent from './MyComponent';

Scenario B: The Named Export Mismatch

Named exports allow you to export multiple things from one file, but they require precision.

Wrong:

// MyComponent.js
export const MyComponent = () => <div>Hello</div>;

// App.js
import MyComponent from './MyComponent'; // Error! You're looking for a default that doesn't exist.

Right:

import { MyComponent } from './MyComponent';

2. The "Barrel File" Headache (index.js)

Using index.js files to clean up folder imports is a great pattern until it breaks. If you import from ./components instead of ./components/Button, your index.js must be perfectly mapped.

Consider this structure:

components/
  ├── Button.js (using export default)
  └── index.js

Your index.js should look like this:

export { default as Button } from './Button';

A single missing line in this file will leave your application trying to render undefined. If you just added a new UI component, double-check that you actually added it to the barrel file before trying to use it elsewhere.

3. Circular Dependencies: The Infinite Loop

This is the trickiest version of the error. If Component A imports Component B, but Component B also imports Component A, one of them will load as undefined because the module system hasn't finished parsing the loop.

If you suspect a loop, move shared logic or small sub-components into a third file, like SharedUtils.js. This breaks the cycle and lets both components import their dependencies safely.

4. Case Sensitivity in Production

Local development on macOS is often case-insensitive. You might import ./Mybutton when the file is actually MyButton.js, and it will work fine on your laptop. However, once you deploy to a Linux environment like Vercel or AWS, the build will fail or the reference will resolve to undefined.

Always match your file casing exactly. It saves hours of debugging "it works on my machine" issues.

The 30-Second Verification Fix

Don't guess. Use a console.log right before your component breaks. It is the fastest way to confirm your suspicions.

import { MyComponent } from './MyComponent';

// Check this in the browser console
console.log("Is MyComponent defined?", MyComponent);

const App = () => {
  return <MyComponent />;
};

If the log says undefined, you’ve confirmed the issue is the import/export bridge, not your JSX syntax.

Pro-Tips for Prevention

  • Stick to Named Exports: I prefer export const MyComponent... because your IDE will auto-complete the import correctly 100% of the time.
  • Adopt TypeScript: TS catches this before you even hit 'Save'. It won't allow an import that doesn't exist in the source file.
  • Watch Third-Party Updates: Major versions of libraries often change their exports. If you recently updated framer-motion or lucide-react, check their docs to see if a named export became a default (or vice versa).

Related Error Notes