6.3 KiB
6.3 KiB
title, impact, impactDescription, type, tags
| title | impact | impactDescription | type | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Fix "No Active Pinia" Error - Store Setup Timing | HIGH | Using Pinia stores before app.use(pinia) causes "getActivePinia was called but there was no active Pinia" error | gotcha |
|
Fix "No Active Pinia" Error - Store Setup Timing
Impact: HIGH - The error "getActivePinia() was called but there was no active Pinia" is one of the most common Pinia errors. It occurs when you try to use a store before Pinia has been installed on the Vue app, causing your application to crash.
Task Checklist
- Ensure
app.use(pinia)is called beforeapp.mount() - Ensure
app.use(pinia)is called beforeapp.use(router)if router guards use stores - Never call
useXxxStore()in module-level (top-level) code - Only call
useXxxStore()inside setup functions, composables, or after app initialization - Check for
<script setup>vs<script>- the latter runs too early
The Error
[🍍]: "getActivePinia()" was called but there was no active Pinia.
Did you forget to install pinia?
Common Cause 1: Wrong Plugin Order
// main.js - WRONG ORDER
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from './router' // Router uses a store in navigation guard
import App from './App.vue'
const app = createApp(App)
// WRONG: Router is installed first, but its guards use stores
app.use(router) // Router guard calls useAuthStore() - FAILS!
app.use(createPinia())
app.mount('#app')
Fix: Install Pinia first:
// main.js - CORRECT ORDER
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from './router'
import App from './App.vue'
const app = createApp(App)
// CORRECT: Pinia installed before anything that uses stores
app.use(createPinia())
app.use(router) // Now router guards can safely use stores
app.mount('#app')
Common Cause 2: Store Used at Module Level
// api.js - WRONG: Module-level store usage
import { useAuthStore } from '@/stores/auth'
// This runs immediately when the module is imported!
const authStore = useAuthStore() // ERROR: No active Pinia yet
export function fetchUser() {
return fetch('/api/user', {
headers: {
Authorization: `Bearer ${authStore.token}`
}
})
}
Fix: Call useStore inside functions:
// api.js - CORRECT: Store used inside function
import { useAuthStore } from '@/stores/auth'
export function fetchUser() {
// Store is accessed when function is called, not when module loads
const authStore = useAuthStore()
return fetch('/api/user', {
headers: {
Authorization: `Bearer ${authStore.token}`
}
})
}
Common Cause 3: Script Tag Missing "setup"
<!-- WRONG: <script> runs before component setup -->
<script>
import { useUserStore } from '@/stores/user'
// This runs too early, before the component is set up
const userStore = useUserStore() // ERROR!
export default {
// ...
}
</script>
Fix: Use <script setup> or move to setup function:
<!-- CORRECT: <script setup> runs at the right time -->
<script setup>
import { useUserStore } from '@/stores/user'
// This runs during component setup, Pinia is active
const userStore = useUserStore() // Works!
</script>
<!-- CORRECT: Options API with setup function -->
<script>
import { useUserStore } from '@/stores/user'
export default {
setup() {
// Called during component initialization
const userStore = useUserStore() // Works!
return { userStore }
}
}
</script>
Common Cause 4: mapStores with Parentheses
<script>
import { mapStores } from 'pinia'
import { useProductsStore } from '@/stores/products'
export default {
computed: {
// WRONG: Called the function instead of passing it
...mapStores(useProductsStore()) // ERROR!
}
}
</script>
Fix: Pass the function reference, not the result:
<script>
import { mapStores } from 'pinia'
import { useProductsStore } from '@/stores/products'
export default {
computed: {
// CORRECT: Pass the function without calling it
...mapStores(useProductsStore) // No parentheses!
}
}
</script>
Common Cause 5: Router Guards Before Pinia
// router/index.js - WRONG
import { createRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
const router = createRouter({ /* ... */ })
// This guard is registered immediately
router.beforeEach((to) => {
// When this runs during app startup, Pinia might not be ready
const authStore = useAuthStore() // May fail!
if (to.meta.requiresAuth && !authStore.isLoggedIn) {
return '/login'
}
})
Fix: Use lazy store access or ensure plugin order:
// router/index.js - CORRECT
import { createRouter } from 'vue-router'
const router = createRouter({ /* ... */ })
router.beforeEach((to) => {
// Dynamically import to avoid module-level execution
const { useAuthStore } = await import('@/stores/auth')
const authStore = useAuthStore()
if (to.meta.requiresAuth && !authStore.isLoggedIn) {
return '/login'
}
})
// OR ensure main.js has correct order:
// app.use(pinia)
// app.use(router)
Debugging Checklist
When you see "No active Pinia":
- Check main.js order: Is
app.use(pinia)before other plugins? - Search for top-level useStore calls: Any store usage outside functions/setup?
- Check script tags: Using
<script>instead of<script setup>? - Check mapStores usage: Using
useStore()instead ofuseStore? - Check import chains: Does an early import trigger store usage?
Safe Pattern: Conditional Store Access
// For code that might run before Pinia is ready
import { getActivePinia } from 'pinia'
export function safelyUseStore() {
const pinia = getActivePinia()
if (!pinia) {
console.warn('Pinia not initialized yet')
return null
}
const { useUserStore } = await import('@/stores/user')
return useUserStore()
}