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