This error occurs when attempting to render a JavaScript Symbol directly in JSX or pass it as a React child. React cannot render Symbols because they are non-serializable primitive types that have no string representation suitable for DOM rendering.
This error is thrown by React when you try to use a JavaScript Symbol as a child element in JSX. React's rendering engine only accepts specific types as valid children: strings, numbers, React elements, fragments, portals, booleans, null, and undefined. Symbols are primitive JavaScript types created with Symbol() or Symbol.for() that serve as unique identifiers, but they cannot be serialized or converted to strings for DOM rendering. React's internal reconciliation process expects to work with renderable content or values it can safely skip (like null/undefined/booleans). When it encounters a Symbol, it cannot determine how to represent it in the DOM, leading to this error. This commonly happens when Symbol values leak into component props or JSX expressions, either through direct rendering attempts or when objects containing Symbol properties are accidentally passed to components. The error is a safeguard to prevent runtime failures in the browser, as the DOM API has no way to handle Symbol types as text content or attributes.
Check your component's render logic for any direct Symbol references. Look for Symbol() or Symbol.for() calls in JSX expressions:
// WRONG - Symbol cannot be rendered
function MyComponent() {
const uniqueId = Symbol('id');
return <div>{uniqueId}</div>; // Error!
}
// WRONG - Symbol in props
function Badge({ icon }) {
return <span>{icon}</span>;
}
<Badge icon={Symbol('badge')} /> // Error!Use your browser console's error stack trace to identify the exact component and line number where the Symbol is being rendered.
If you need to show the Symbol value for debugging or logging purposes, convert it to a string first:
// CORRECT - Convert to string
function MyComponent() {
const uniqueId = Symbol('id');
return <div>{String(uniqueId)}</div>; // Shows "Symbol(id)"
// or
return <div>{uniqueId.toString()}</div>;
// or
return <div>{uniqueId.description}</div>; // Shows just "id"
}Use .description property for cleaner output without the "Symbol()" wrapper.
Refactor your code to keep Symbol values in logic layer and use strings/numbers for UI:
// CORRECT - Symbol for internal use, string for display
const STATUS_PENDING = Symbol('pending');
const STATUS_COMPLETE = Symbol('complete');
const STATUS_LABELS = {
[STATUS_PENDING]: 'Pending',
[STATUS_COMPLETE]: 'Complete'
};
function TaskStatus({ status }) {
return <div>{STATUS_LABELS[status]}</div>; // Renders string
}
<TaskStatus status={STATUS_PENDING} /> // Works!This pattern keeps type-safe Symbol constants while rendering human-readable strings.
React keys must be strings or numbers. If you're using Symbol for unique keys, replace with string-based identifiers:
// WRONG - Cannot convert Symbol to string for key
items.map(item => (
<div key={Symbol(item.id)}>{item.name}</div> // Error!
));
// CORRECT - Use string or number keys
items.map(item => (
<div key={item.id}>{item.name}</div>
));
// Or generate stable string keys
items.map((item, index) => (
<div key={`item-${item.id}-${index}`}>{item.name}</div>
));Use crypto.randomUUID() or nanoid library if you need unique string identifiers.
If spreading objects that might contain Symbol properties, filter them out first:
// WRONG - May spread Symbol properties
const obj = { name: 'Test', [Symbol('internal')]: 'value' };
return <Component {...obj} />; // Risk if Component renders children
// CORRECT - Filter to only string/number keys
const safeProps = Object.keys(obj).reduce((acc, key) => {
acc[key] = obj[key];
return acc;
}, {});
return <Component {...safeProps} />;
// Or use explicit prop passing
return <Component name={obj.name} />;This prevents accidental Symbol props from reaching rendering logic.
Use proper typing to catch Symbol usage at compile time:
// CORRECT - Strict children typing
interface MyComponentProps {
children: React.ReactNode; // Excludes Symbols
}
// CORRECT - Strict prop typing
interface BadgeProps {
icon: string | React.ReactElement; // No Symbols
label: string;
}
// Use satisfies for inline type checking
const config = {
icon: '🎉', // OK
label: 'Status'
} satisfies BadgeProps;
// This would error at compile time:
// const badConfig = {
// icon: Symbol('bad'),
// label: 'Status'
// } satisfies BadgeProps; // Type error!Enable strict TypeScript checking to catch these issues before runtime.
If the error appears with external data, check for unexpected Symbol values:
// Add defensive check in data fetching
async function fetchData() {
const response = await fetch('/api/data');
const data = await response.json();
// Inspect for Symbols (shouldn't be in JSON, but check parsed data)
console.log('Data keys:', Object.keys(data));
console.log('All keys including Symbols:',
Object.getOwnPropertySymbols(data));
return data;
}
// Add runtime validation
function sanitizeData(obj) {
return JSON.parse(JSON.stringify(obj)); // Removes Symbols
}JSON.parse/stringify will strip Symbol properties, providing a safe data structure for rendering.
Well-known Symbols: Be especially careful with JavaScript's well-known Symbols like Symbol.iterator, Symbol.toStringTag, Symbol.hasInstance, etc. These are often used in custom data structures but should never leak into React rendering. When iterating over objects with Symbol properties, use Object.keys() or Object.getOwnPropertyNames() to exclude them.
Redux and State Management: When using Redux or other state management libraries that allow Symbol keys in state, ensure your selectors return only serializable data. State serialization checks in Redux DevTools can help catch these issues early. Avoid storing Symbols in Redux state if they're meant to be rendered.
Iterator Protocol: Be cautious with custom iterables that use Symbol.iterator. If you pass an iterator directly to JSX expecting it to render its values, it will fail. Convert iterators to arrays with the spread operator: {[...iterator()]} instead of {iterator()}.
React 18+ Changes: React's rendering engine in version 18 and above has stricter type checking for children. Code that may have failed silently in older versions will now throw explicit errors about invalid children types during development.
Performance: The error occurs during React's render phase, so it will prevent the entire component tree from rendering. No partial rendering occurs, making debugging easier as the error is immediate and specific.
Prevention Pattern: Establish a convention in your codebase that Symbol values are always prefixed with SYMBOL_ (e.g., SYMBOL_STATUS_PENDING) and document that these should never be passed to React components directly. Use a linter rule or TypeScript plugin to detect Symbol usage in JSX when possible.
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite