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

  1. Wrap the consuming component (and its ancestors) inside <AuthProvider>.
  2. In tests, wrap with the provider (or a custom render helper that includes it).
  3. If a portal is involved, render it within the same React tree under AuthProvider.
  4. Check component ordering so the provider mounts before any consumer.
  5. 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

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


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/f1d6f29cbfa27e6a. Report an issue: GitHub.