Fix: Injection Not Found in Vue.js

Error message:
injection "{key}" not found.
Composition API 2025-01-25

What Causes This Warning?

This warning appears when you try to inject() a value that hasn’t been provide()d by any ancestor component. This usually means the provider component is missing or the injection key doesn’t match.

The Problem

<!-- ChildComponent.vue -->
<script setup>
import { inject } from 'vue'

// ❌ No ancestor provided 'theme'
const theme = inject('theme') // Warning: injection "theme" not found
</script>

The Fix

Ensure Provider Exists

<!-- App.vue (parent) -->
<script setup>
import { provide, reactive } from 'vue'

// ✅ Provide the value
const theme = reactive({ color: 'dark' })
provide('theme', theme)
</script>

<template>
  <ChildComponent />
</template>
<!-- ChildComponent.vue -->
<script setup>
import { inject } from 'vue'

// ✅ Now it works
const theme = inject('theme')
</script>

Provide Default Value

// ✅ Provide a default value
const theme = inject('theme', { color: 'light' })

// ✅ Factory function for default (called only if needed)
const theme = inject('theme', () => {
  return { color: 'light' }
}, true) // true = treat as factory

Use Symbols for Keys

// keys.js
export const ThemeKey = Symbol('theme')

// Provider
import { ThemeKey } from './keys'
provide(ThemeKey, theme)

// Consumer
import { ThemeKey } from './keys'
const theme = inject(ThemeKey) // No typo possible!

Common Scenarios

Missing Provider in Component Tree

<!-- ❌ Provider not in ancestor chain -->
<App>
  <ThemeProvider>  <!-- Provides theme -->
    <PageA />      <!-- Can inject theme -->
  </ThemeProvider>
  <PageB />        <!-- ❌ Cannot inject theme - not a descendant! -->
</App>

<!-- ✅ Move provider higher -->
<App>
  <ThemeProvider>
    <PageA />
    <PageB />      <!-- ✅ Now can inject theme -->
  </ThemeProvider>
</App>

Key Mismatch

// ❌ Keys don't match
provide('userTheme', theme)
const theme = inject('theme') // Different key!

// ✅ Use same key
provide('theme', theme)
const theme = inject('theme')

// ✅✅ Better: use Symbol
const ThemeKey = Symbol('theme')
provide(ThemeKey, theme)
const theme = inject(ThemeKey)

Optional Injection

// For truly optional dependencies
const analytics = inject('analytics', null)

function trackEvent(name) {
  // Only track if analytics is available
  analytics?.track(name)
}

TypeScript with Injection

// types.ts
import type { InjectionKey } from 'vue'

interface Theme {
  color: string
  toggle: () => void
}

export const ThemeKey: InjectionKey<Theme> = Symbol('theme')

// Provider
import { ThemeKey } from './types'
const theme: Theme = reactive({
  color: 'dark',
  toggle() { /* ... */ }
})
provide(ThemeKey, theme)

// Consumer - fully typed!
const theme = inject(ThemeKey) // Type: Theme | undefined
const theme = inject(ThemeKey, { color: 'light', toggle: () => {} }) // Type: Theme

App-Level vs Component-Level

// main.js - App-level provide
const app = createApp(App)
app.provide('config', { apiUrl: '...' })

// Component-level provide
export default {
  setup() {
    provide('localData', { /* ... */ })
  }
}

// App-level is available everywhere
// Component-level only in descendants

Creating Safe Composables

// useTheme.js
import { inject, computed } from 'vue'

const ThemeKey = Symbol('theme')
const defaultTheme = { color: 'light', fontSize: 14 }

export function useTheme() {
  const theme = inject(ThemeKey, null)

  if (!theme) {
    console.warn('useTheme: No theme provider found, using defaults')
    return defaultTheme
  }

  return theme
}

// Or throw if required
export function useRequiredTheme() {
  const theme = inject(ThemeKey)

  if (!theme) {
    throw new Error(
      'useRequiredTheme requires a ThemeProvider ancestor. ' +
      'Wrap your app with <ThemeProvider>.'
    )
  }

  return theme
}

Quick Checklist

  • Verify provider exists in component ancestry
  • Check that injection key matches exactly
  • Use Symbols to prevent key typos
  • Provide default values for optional injections
  • Move providers higher in tree if needed
  • Use TypeScript InjectionKey for type safety