This error occurs when a component tries to consume a React Context value but receives undefined instead. It typically happens when the component is not wrapped in the corresponding Context Provider, or when the Provider is missing a value prop.
This error indicates that a component is attempting to read from a React Context using `useContext()`, but the context value is undefined. React Context is designed to share data across the component tree without prop drilling, but it requires proper setup with both `createContext()` and a `<Provider>` component. When you call `useContext(SomeContext)`, React searches up the component tree to find the nearest `<SomeContext.Provider>`. If it finds one, it returns the `value` prop from that provider. If no provider exists in the ancestor tree, React returns the default value specified in `createContext(defaultValue)`. However, if a provider exists but doesn't pass a `value` prop (or explicitly passes `undefined`), the context will be undefined regardless of any default value. This error often surfaces when developers forget to wrap their component tree with the appropriate Provider, incorrectly structure their component hierarchy, or forget to pass the `value` prop to the Provider component. It's particularly common when refactoring code or working with deeply nested component structures.
Check that your component using useContext() is a child (at any level) of the corresponding Provider:
import { createContext, useContext } from 'react';
const ThemeContext = createContext(undefined);
// ❌ WRONG: Consumer not wrapped by Provider
function App() {
return (
<div>
<ThemeButton /> {/* This will get undefined */}
</div>
);
}
// ✅ CORRECT: Consumer wrapped by Provider
function App() {
return (
<ThemeContext.Provider value={{ theme: 'dark' }}>
<ThemeButton /> {/* This will receive the value */}
</ThemeContext.Provider>
);
}
function ThemeButton() {
const theme = useContext(ThemeContext);
// theme will be undefined in the wrong example
return <button>{theme?.theme}</button>;
}Ensure the Provider is positioned higher in the component tree than any component that needs to consume the context.
Make sure your Provider component includes the value prop with the data you want to share:
import { createContext, useState } from 'react';
const UserContext = createContext(undefined);
// ❌ WRONG: Missing value prop
function App() {
const [user, setUser] = useState({ name: 'John' });
return (
<UserContext.Provider> {/* No value prop! */}
<UserProfile />
</UserContext.Provider>
);
}
// ✅ CORRECT: value prop provided
function App() {
const [user, setUser] = useState({ name: 'John' });
return (
<UserContext.Provider value={{ user, setUser }}>
<UserProfile />
</UserContext.Provider>
);
}The value prop is what gets passed to all consuming components. Without it, the context will be undefined.
Implement a custom hook that checks for undefined and provides a clear error message:
import { createContext, useContext, ReactNode } from 'react';
type ThemeContextType = {
theme: 'light' | 'dark';
toggleTheme: () => void;
};
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
// Custom hook with validation
export function useTheme() {
const context = useContext(ThemeContext);
if (context === undefined) {
throw new Error('useTheme must be used within a ThemeProvider');
}
return context;
}
// Provider component
export function ThemeProvider({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState<'light' | 'dark'>('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Usage
function MyComponent() {
const { theme, toggleTheme } = useTheme(); // Will throw clear error if outside provider
return <button onClick={toggleTheme}>Current: {theme}</button>;
}This pattern immediately identifies when components are used outside their Provider and provides actionable error messages.
For cases where a default makes sense, provide it in createContext():
// ❌ WRONG: undefined default with no validation
const SettingsContext = createContext(undefined);
// ✅ BETTER: Meaningful default value
const SettingsContext = createContext({
fontSize: 'medium',
colorMode: 'light',
updateSettings: () => {
console.warn('SettingsProvider not found, using default context');
}
});
// ✅ BEST: Combine default with custom hook validation
const SettingsContext = createContext<SettingsContextType | undefined>(undefined);
function useSettings() {
const context = useContext(SettingsContext);
if (context === undefined) {
throw new Error('useSettings must be used within SettingsProvider');
}
return context;
}Note that default values are only used when there is no Provider in the ancestor tree at all. If a Provider exists but passes value={undefined}, the default won't be used.
If your context value depends on async operations, handle the loading state properly:
import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
type User = { id: string; name: string; };
type AuthContextType = {
user: User | null;
loading: boolean;
};
const AuthContext = createContext<AuthContextType | undefined>(undefined);
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate async auth check
fetchCurrentUser()
.then(setUser)
.finally(() => setLoading(false));
}, []);
return (
<AuthContext.Provider value={{ user, loading }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth() {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth must be used within AuthProvider');
}
return context;
}
// Usage
function UserProfile() {
const { user, loading } = useAuth();
if (loading) return <div>Loading...</div>;
if (!user) return <div>Not logged in</div>;
return <div>Welcome, {user.name}</div>;
}Always provide a value to the Provider, even during loading states. Include loading flags to handle the async nature of your data.
TypeScript Best Practices
When working with TypeScript, you have several options for typing context:
1. Undefined with validation: Set the context type to ContextType | undefined and use a custom hook to validate and narrow the type. This forces consumers to use your validation hook.
2. Non-null assertion: Use createContext({} as ContextType) to avoid undefined, but this sacrifices compile-time safety and can hide provider placement errors.
3. Separate Provider component: Create a custom Provider component that encapsulates the context creation and value management, exposing only a typed hook for consumption.
Multiple Context Instances
If you have duplicate imports or build tool issues (like symlinks), you might have multiple instances of the same context. You can debug this by assigning the context to a global:
window.MyContext1 = MyContext; // In provider file
window.MyContext2 = MyContext; // In consumer file
console.log(window.MyContext1 === window.MyContext2); // Should be trueIf they're not equal, you have a build configuration issue that needs resolving.
Context Composition
For complex applications, consider composing multiple smaller contexts instead of one large context. This improves performance (consumers only re-render when their specific context changes) and reduces the chance of undefined errors:
function App() {
return (
<ThemeProvider>
<AuthProvider>
<SettingsProvider>
<AppContent />
</SettingsProvider>
</AuthProvider>
</ThemeProvider>
);
}Server-Side Rendering Considerations
With Next.js or other SSR frameworks, ensure your providers are set up correctly on both client and server. Some contexts may need to be client-only, marked with 'use client' directive in Next.js 13+.
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