spree/spree · error · Error
useStore must be used within a StoreProvider
Error message
useStore must be used within a StoreProvider
What it means
Hook from @spree/dashboard-core reading StoreContext, created only by <StoreProvider storeId={...}>. The provider TanStack-Query-fetches the store record (keyed ['store', storeId]) and derives currencies, locales, timezone and defaults for the whole SPA. useStore() throws when called outside that provider.
Source
Thrown at packages/dashboard-core/src/providers/store-provider.tsx:108
isLoading: query.isLoading,
currencies,
locales,
availableLocales,
defaultCurrency,
defaultLocale,
timezone,
refetch: query.refetch,
}}
>
{children}
</StoreContext.Provider>
)
}
export function useStore(): StoreContextValue {
const context = useContext(StoreContext)
if (!context) {
throw new Error('useStore must be used within a StoreProvider')
}
return context
}
View on GitHub (pinned to 06bf66a868)
Solutions
- Render the component inside <StoreProvider storeId={storeId}> — in the SPA this is the authenticated $storeId route layout
- Ensure storeId is available (route params) before rendering consumers; gate on the param existing
- In tests, wrap with a provider stack that includes StoreProvider with a test storeId
- For components usable outside a store context (account-level pages), take currency/locale/timezone via props instead of useStore()
Example fix
// before
const { store, timezone } = useStore() // throws: no StoreProvider above
// after — inside the store route, where the id is known
<Route path="/stores/$storeId">
{({ params }) => (
<StoreProvider storeId={params.storeId}>
<StorePages />
</StoreProvider>
)}
</Route> Defensive patterns
Strategy: validation
Validate before calling
// Ensure a storeId exists before rendering anything that (transitively) calls useStore()
function StoreRoute({ storeId }: { storeId?: string }) {
if (!storeId) return <StoreLoading /> // never render consumers without the id
return (
<StoreProvider storeId={storeId}>
<StorePages />
</StoreProvider>
)
} Prevention
- Render the whole store workspace under the $storeId route layout so StoreProvider is unconditionally present
- Remember StoreProvider needs an AuthProvider ancestor and a storeId prop — check both when wiring custom hosts
- In tests, wrap with StoreProvider plus a test storeId; most formatting components depend on its currency/timezone
- Components shared across store/account contexts should take currency/locale/timezone via props
When it happens
Trigger: Calling useStore() in a component rendered outside <StoreProvider>: pages or layout chrome mounted before the store route parameter exists (no storeId to pass), components on unauthenticated routes, portal-rendered overlays, or isolated tests without the provider wrapper.
Common situations: Custom host apps that skip the store route wrapper; upgrading @spree/dashboard-core where provider composition moved into the $storeId route layout; tests rendering any component that transitively calls useStore (currency formatting, <StoreDatePicker>); forgetting that StoreProvider requires both a storeId prop and an <AuthProvider> ancestor (it calls useAuth).
Related errors
- useCommandPalette must be used within a CommandPaletteProvid
- usePermissions must be used within a PermissionProvider
- useConfirm must be used within ConfirmProvider
- useTheme must be used within <ThemeProvider>
- useChart must be used within ChartContainer
AI-assisted analysis of spree/spree@06bf66a868 (2026-08-21).
Data as JSON: /api/errors/47ba9ec3e17271eb.
Report an issue: GitHub.