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

Diagnostic Flow

text
Symptom → Console / terminal error → classify → fix one layer → reload
LayerWhere to look
TerminalVite compile error, missing import
Browser consoleRuntime exception, Vue warn
NetworkFailed chunk, API 4xx/5xx, CORS
Vue DevToolsComponent 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.html has <div id="app">
  • Confirm createApp(App).mount('#app')

See First Vue Application.

Failed to resolve import "@/..."

Cause: Path alias not configured.

Fix vite.config.ts:

typescript
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 pathsTypeScript With Vue.

npm run dev: port already in use

Fix:

bash
# change port in vite.config.ts server.port
# or kill process on 5173

Reactivity Issues

Updated data but UI unchanged

Cause: Lost reactivity—destructured reactive without toRefs, replaced object incorrectly.

Fix:

typescript
// 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.htmlBuild 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.

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:

typescript
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:

typescript
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):

  1. Vite server.proxyFetching API
  2. 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:

typescript
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 / symptomChapter
CORS17, Flask 20
Router refresh 40420, 27
Pinia outside setup16
Lost reactivity05
Auth redirect loop15, 25
v-model on component08, 09
Lazy route chunk failed15, 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.