Vue Troubleshooting
Introduction
Most Vue bugs fall into a few buckets: build/config errors, lost reactivity, router/auth issues, CORS, or TypeScript tooling. This chapter maps symptoms → cause → fix and links back to the chapters where each topic is taught.
Prerequisites
- You have run
npm run devon a Vue 3 + Vite project — Environment and create-vue - Browser DevTools console open
Diagnostic Flow
Symptom → Console / terminal error → classify → fix one layer → reload| Layer | Where to look |
|---|---|
| Terminal | Vite compile error, missing import |
| Browser console | Runtime exception, Vue warn |
| Network | Failed chunk, API 4xx/5xx, CORS |
| Vue DevTools | Component tree, Pinia state, route |
Dev Server and Build
White screen, no errors in terminal
Cause: Runtime error before mount, wrong #app selector, empty main.ts.
Fix:
- Open browser console
- Confirm
index.htmlhas<div id="app"> - Confirm
createApp(App).mount('#app')
Failed to resolve import "@/..."
Cause: Path alias not configured.
Fix vite.config.ts:
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
});Match tsconfig paths — TypeScript With Vue.
npm run dev: port already in use
Fix:
# change port in vite.config.ts server.port
# or kill process on 5173Reactivity Issues
Updated data but UI unchanged
Cause: Lost reactivity—destructured reactive without toRefs, replaced object incorrectly.
Fix:
// Wrong — breaks reactivity
const { count } = reactive({ count: 0 });
// Right
const state = reactive({ count: 0 });
// or
const count = ref(0);See Reactivity: ref and reactive.
Async data assigned but template empty briefly
Expected: Initial render before fetch completes. Show loading state — Fetching API.
watch not firing
Cause: Watching primitive extracted from ref without .value in setup, or wrong deep / immediate options.
Fix: Computed and Watch.
Template and Components
v-for key warning / list reorder bugs
Cause: key on index or non-unique value.
Fix: Stable id: :key="item.id" — Template Syntax.
Component not registered / unknown custom element
Cause: Forgot import in <script setup> or typo in tag name.
Fix: Import component; use PascalCase in SFC (Vue resolves both cases).
Prop mutation warning
Cause: Child assigns to props.x.
Fix: Emit event or local copy — Components.
Router
404 on refresh in production
Cause: Server looks for /dashboard file; SPA needs fallback.
Fix: Nginx try_files $uri /index.html — Build and Deploy, Docker CI.
Infinite redirect login ↔ dashboard
Cause: Guard checks wrong token; login route also requiresAuth.
Fix: meta.public: true on login — Router Guards.
Navigation guard never runs
Cause: router.beforeEach registered after first navigation, or wrong router instance.
Fix: Register guards in router/index.ts before app.use(router).
Pinia
getActivePinia() was called with no active Pinia
Cause: useStore() outside setup/component, before app.use(pinia).
Fix:
const app = createApp(App);
const pinia = createPinia();
app.use(pinia);
app.use(router);
app.mount("#app");See Pinia.
Store updates but component stale
Cause: Destructured state without storeToRefs.
Fix:
const store = useTodoStore();
const { items } = storeToRefs(store);API and CORS
Access-Control-Allow-Origin blocked
Cause: Browser blocks cross-origin response; dev calls http://localhost:8000 from 5173.
Fix (pick one):
- Vite
server.proxy— Fetching API - Backend CORSMiddleware / Flask-CORS — Flask CORS
401 on every request after login
Cause: Missing Authorization header, expired token, wrong Bearer format.
Fix: Admin auth project, FastAPI JWT.
TypeScript and Editor
defineProps type errors in template
Fix: Use defineProps<{ id: number }>() with lang="ts" — TypeScript With Vue.
vue-tsc fails but dev works
Cause: Stricter check than Vite esbuild.
Fix: Run npm run type-check locally; fix reported types.
Volar vs Vetur red squiggles
Cause: Both extensions active.
Fix: Disable Vetur; use Vue - Official (Volar) for Vue 3.
Testing
mount fails: inject() can only be used...
Cause: Component needs Pinia or Router plugins.
Fix:
mount(Component, {
global: {
plugins: [createPinia(), router],
},
});See Testing.
SSR / Nuxt (If You Try Nuxt)
Hydration mismatch
Cause: Server HTML differs from client render (random ids, Date.now() in template, browser-only APIs on server).
Fix: Render same markup on server and client; use ClientOnly or onMounted for client-only bits — SSR intro.
Quick Reference Table
| Error / symptom | Chapter |
|---|---|
| CORS | 17, Flask 20 |
| Router refresh 404 | 20, 27 |
| Pinia outside setup | 16 |
| Lost reactivity | 05 |
| Auth redirect loop | 15, 25 |
| v-model on component | 08, 09 |
| Lazy route chunk failed | 15, Network tab |
FAQ
Where is the full error message?
Terminal for Vite; browser console for runtime; Network tab for API.
Still stuck?
Minimal reproduction: strip to one component, one route, one store action.
Production-only bug?
Compare npm run build && npm run preview with dev—env vars differ.
Vue 2 vs Vue 3 error?
This track is Vue 3 only—check createApp not new Vue.
Devtools not showing?
Install Vue DevTools extension; confirm production build not stripping devtools in dev mode.