React throws this error when you pass a string value where a component is expected. This commonly occurs when importing components incorrectly, passing component names as strings, or when dynamic component resolution fails.
This error occurs when React's component validation detects that you're trying to render something that looks like a component but is actually a string value. React expects components to be one of three things: a function component, a class component, or a ForwardRef component. When you accidentally pass a string instead of the actual component reference, React cannot render it and throws this error. This usually happens during the JSX transformation process. When you write JSX like <MyComponent />, React internally calls React.createElement(MyComponent). If MyComponent is a string rather than an actual component, React's validation fails immediately. The error is React's way of protecting you from runtime issues. If React tried to render a string as if it were a component, it would cause unpredictable behavior or crashes. Instead, it fails fast with a clear error message indicating exactly what type was expected versus what was received.
Verify that you're importing the component correctly. The most common issue is mixing up default and named exports.
Named export (correct):
// Component file
export const MyComponent = () => <div>Hello</div>;
// Usage file
import { MyComponent } from './MyComponent';
<MyComponent />Default export (correct):
// Component file
const MyComponent = () => <div>Hello</div>;
export default MyComponent;
// Usage file
import MyComponent from './MyComponent';
<MyComponent />Incorrect (causes error):
// Component file uses named export
export const MyComponent = () => <div>Hello</div>;
// Usage file tries default import
import MyComponent from './MyComponent'; // Returns undefined!
<MyComponent /> // Error: undefined is not a valid componentMake sure the component is properly exported from its source file.
Check the export:
// MyComponent.tsx
const MyComponent = () => {
return <div>Content</div>;
};
// Missing export! This will cause import to fail
// export default MyComponent; // Add this lineVerify in usage file:
import MyComponent from './MyComponent';
// Log to check what was imported
console.log('MyComponent:', MyComponent);
// Should show: function or class, not undefined or string
<MyComponent />If you're dynamically selecting components, ensure you're mapping to actual component references, not strings.
Incorrect (causes error):
const componentMap = {
header: 'Header', // String, not component!
footer: 'Footer'
};
const ComponentToRender = componentMap[type];
<ComponentToRender /> // Error!Correct:
import Header from './Header';
import Footer from './Footer';
const componentMap = {
header: Header, // Actual component reference
footer: Footer
};
const ComponentToRender = componentMap[type];
<ComponentToRender /> // Works!Circular dependencies can cause imports to resolve to undefined at runtime.
Identify circular dependency:
# Use a tool like madge to detect cycles
npx madge --circular src/Example of circular dependency:
// ComponentA.tsx
import ComponentB from './ComponentB';
export const ComponentA = () => <ComponentB />;
// ComponentB.tsx
import ComponentA from './ComponentA'; // Circular!
export const ComponentB = () => <ComponentA />;Fix by extracting shared dependencies:
// SharedTypes.ts (new file)
export interface SharedProps { /* ... */ }
// ComponentA.tsx
import { SharedProps } from './SharedTypes';
import ComponentB from './ComponentB';
// ComponentB.tsx
import { SharedProps } from './SharedTypes';
// Don't import ComponentAIf using React.forwardRef, ensure you're returning it correctly.
Incorrect:
const MyComponent = React.forwardRef((props, ref) => {
return 'div'; // String instead of JSX!
});Correct:
const MyComponent = React.forwardRef((props, ref) => {
return <div ref={ref}>{props.children}</div>;
});
export default MyComponent;When using code-splitting with React.lazy, ensure the dynamic import returns a valid component.
Incorrect:
const LazyComponent = React.lazy(() =>
import('./MyComponent').then(module => module.componentName) // Returns string!
);Correct:
// Default export
const LazyComponent = React.lazy(() => import('./MyComponent'));
// Or named export
const LazyComponent = React.lazy(() =>
import('./MyComponent').then(module => ({ default: module.MyComponent }))
);
// Usage with Suspense
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>TypeScript considerations:
If you're using TypeScript, you can prevent many of these errors at compile time with proper typing:
import { ComponentType } from 'react';
// Type-safe component mapping
const componentMap: Record<string, ComponentType<any>> = {
header: Header,
footer: Footer
};
// TypeScript will error if you try to add a string
// componentMap.invalid = 'NotAComponent'; // Type error!Debugging in development:
React DevTools won't show much for this error since the component never renders. Instead:
1. Add console.log statements before the failing render
2. Check the Network tab to ensure component files are loading
3. Use breakpoints in your bundler's source maps to inspect imported values
Common framework-specific issues:
- Next.js: Server Components cannot use React.forwardRef. Convert to Client Component with 'use client' directive
- Remix: Check that your component exports match the framework's conventions (default vs named)
- Vite: Ensure your JSX pragma is configured correctly in vite.config.ts
Performance impact:
While this error prevents rendering entirely, be aware that having many dynamic component mappings can impact bundle size. Consider code-splitting with React.lazy for large component libraries.
Related React internals:
React's createElement function performs type validation before creating element objects. The valid types are:
- String (built-in HTML tags like 'div', 'span')
- Function (function components)
- Class (class components extending React.Component)
- Symbol (React.Fragment, React.StrictMode)
- ForwardRef object (from React.forwardRef)
Any other type, including plain strings that aren't HTML tag names, will fail validation.
Prop spreading could cause security issues
Prop spreading could cause security issues
Error: error:0308010C:digital envelope routines::unsupported
Error: error:0308010C:digital envelope routines::unsupported
React Hook "useEffect" is called conditionally. React Hooks must be called in the exact same order in every component render.
React Hook useEffect placed inside a condition
Hook can only be called inside the body of a function component
Hook can only be called inside the body of a function component
Rollup failed to resolve import during build
How to fix "Rollup failed to resolve import" in React