This error occurs when React Context is created without a default value (or with undefined) and components try to consume it outside of a Provider. The Consumer receives undefined and fails when trying to access properties or destructure the context value.
This error occurs when you create a React Context using `createContext()` without providing a default value (or explicitly passing `undefined`), and then try to consume that context in a component that isn't wrapped by the corresponding Provider. When Context is consumed outside of a Provider, React falls back to the default value passed to `createContext()`. If that default value is `undefined`, any attempt to destructure it or access its properties will fail. This commonly happens with TypeScript when creating typed contexts, as developers often initialize the context with `undefined` to satisfy type requirements. The error typically manifests as "Cannot read property 'x' of undefined" or "Cannot destructure property 'x' of undefined" when using `useContext` or Context.Consumer in components that aren't properly wrapped by the Provider component.
Create a custom hook that throws a helpful error if context is undefined:
import { createContext, useContext } from 'react';
interface UserContextType {
username: string;
role: string;
}
const UserContext = createContext<UserContextType | undefined>(undefined);
// Custom hook with error checking
export function useUser() {
const context = useContext(UserContext);
if (context === undefined) {
throw new Error('useUser must be used within a UserProvider');
}
return context;
}
export { UserContext };This provides a clear error message pointing to the actual problem instead of cryptic undefined errors.
Verify that all components using the context are wrapped by the Provider:
import { UserContext } from './UserContext';
function App() {
const userData = { username: 'alice', role: 'admin' };
return (
<UserContext.Provider value={userData}>
{/* All components here can safely use useUser() */}
<Dashboard />
<Settings />
</UserContext.Provider>
);
}Check your component tree to ensure the Provider is placed high enough to cover all consumers. Use React DevTools to inspect the component hierarchy.
For TypeScript projects, use a union type that includes null or undefined:
const UserContext = createContext<UserContextType | null>(null);
export function useUser() {
const context = useContext(UserContext);
if (!context) {
throw new Error('useUser must be used within a UserProvider');
}
return context;
}This approach makes it explicit in the type system that the context can be null, forcing you to handle the case properly.
For simple contexts (primitives, enums), provide a sensible default:
type Theme = 'light' | 'dark';
const ThemeContext = createContext<Theme>('light');
// No custom hook needed - consumers always get a valid value
export function useTheme() {
return useContext(ThemeContext);
}This works well for contexts that have reasonable defaults, but isn't suitable for complex state that must come from a Provider.
If you're certain the Provider will always be present, use TypeScript's non-null assertion:
const UserContext = createContext<UserContextType>(undefined!);Warning: This bypasses TypeScript's safety checks. Only use this if you're absolutely sure all consumers will be wrapped by a Provider. The custom hook approach (step 1) is safer and provides better error messages.
When testing components that use context, always provide a test Provider:
import { render } from '@testing-library/react';
import { UserContext } from './UserContext';
function renderWithContext(ui: React.ReactElement, userData = mockUserData) {
return render(
<UserContext.Provider value={userData}>
{ui}
</UserContext.Provider>
);
}
test('displays user name', () => {
renderWithContext(<UserProfile />);
// assertions...
});This ensures your tests don't encounter undefined context values.
Generic Context Factory Pattern: For applications with multiple contexts, create a reusable factory function:
function createGenericContext<T>() {
const Context = createContext<T | undefined>(undefined);
function useGenericContext() {
const context = useContext(Context);
if (context === undefined) {
throw new Error('Context must be used within its Provider');
}
return context;
}
return [useGenericContext, Context.Provider] as const;
}
// Usage:
const [useAuth, AuthProvider] = createGenericContext<AuthContextType>();Default Values vs Provider Pattern: React's documentation notes that the defaultValue argument is primarily useful for testing components in isolation. For production code, the Provider pattern with runtime checks is more robust and provides better error messages.
Optional Chaining Approach: An alternative to custom hooks is using optional chaining everywhere:
const user = useContext(UserContext);
return <div>{user?.username}</div>;However, this silently fails and makes it harder to catch Provider placement bugs. The custom hook approach (with explicit error throwing) is generally preferred.
Context Splitting: If you find yourself constantly checking for undefined context, consider whether your context is too large. Split it into multiple smaller contexts, each with clear Provider boundaries and specific purposes.
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