actualbudget/actual · error
useAuth must be used within an AuthProvider
Error message
useAuth must be used within an AuthProvider
What it means
useAuth is a React context hook that reads the AuthContext created by AuthProvider. If no provider value exists (context === undefined), the hook is being called outside of any <AuthProvider> tree, so there is no auth state to return and the hook throws this descriptive error instead of failing later with an undefined destructuring error.
Source
Thrown at packages/desktop-client/src/auth/AuthProvider.tsx:44
}
return (
!serverUrl ||
userData?.permission?.toUpperCase() === permission?.toUpperCase()
);
};
return (
<AuthContext.Provider value={{ hasPermission }}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => {
const context = useContext(AuthContext);
if (context === undefined) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
};
View on GitHub (pinned to d4334cb6e6)
Solutions
- Wrap the consuming component (and its ancestors) inside <AuthProvider>.
- In tests, wrap with the provider (or a custom render helper that includes it).
- If a portal is involved, render it within the same React tree under AuthProvider.
- Check component ordering so the provider mounts before any consumer.
- If needed, provide a default context value or move auth logic up to the provider boundary.
Example fix
// before
render(<LoginPage />); // throws: outside provider
// after
render(
<AuthProvider>
<LoginPage />
</AuthProvider>
); Defensive patterns
Strategy: type-guard
Validate before calling
const AuthContext = createContext(undefined); // Ensure every consumer is inside <AuthProvider>: check the component tree order in App.tsx before using useAuth.
Type guard
function hasAuthContext(value) {
return value !== undefined && typeof value === 'object' && 'currentUser' in value;
}
export const useAuthSafe = () => {
const ctx = useContext(AuthContext);
return hasAuthContext(ctx) ? ctx : null;
}; Try / catch
// Hooks cannot be wrapped in try/catch; instead use a safe wrapper:
const auth = useAuthSafe();
if (!auth) {
return <AuthProvider><App /></AuthProvider>; // or a loading/error state
} Prevention
- Render <AuthProvider> at the very top of the app tree, above all auth consumers.
- In tests, use a custom render helper that always wraps with AuthProvider.
- Avoid separate React roots for portals that bypass the provider.
- Keep auth consumers as descendants of the provider in code reviews.
When it happens
Trigger: Calling useAuth() in a component rendered above or outside <AuthProvider> (e.g. in the app root before the provider mounts), in a component used in tests without wrapping the render in AuthProvider, in a separate React root (modal portal with a different tree root), or in a module evaluated before the provider exists.
Common situations: Refactoring App.tsx and accidentally moving a consumer outside the provider; writing a Vitest/RTL test that renders a component using useAuth without the provider wrapper; rendering a portal under a different React root.
Related errors
- ServerContext not initialized
- Unitialised context method called: onBudgetAction
- Unitialised context method called: onToggleSummaryCollapse
- Authentication required. Set --password/--session-token, ACT
- Authentication required. Provide --password or --session-tok
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/f1d6f29cbfa27e6a.
Report an issue: GitHub.