vuetifyjs/vuetify · error · Error
foo
Error message
foo
What it means
Thrown by useExpanded() in VDataTable when inject(VDataTableExpandedKey) returns undefined. The composable expects to find expansion state provided by createExpanded() higher in the component tree. (The literal message 'foo' is a known placeholder — it does not change behavior.)
Source
Thrown at packages/vuetify/src/components/VDataTable/composables/expand.ts:83
const rawValue = toRaw(item.value)
return [...expanded.value].some(x => toRaw(x) === rawValue)
}
function toggleExpand (item: DataTableItem) {
expand(item, !isExpanded(item))
}
const data = { expand, expanded, expandOnClick, isExpanded, toggleExpand }
provide(VDataTableExpandedKey, data)
return data
}
export function useExpanded () {
const data = inject(VDataTableExpandedKey)
if (!data) throw new Error('foo')
return data
}
View on GitHub (pinned to 8d153908df)
Solutions
- Only call useExpanded() inside a component that is a descendant of a VDataTable-family component.
- If building a custom table, call createExpanded(...) yourself and provide VDataTableExpandedKey before useExpanded().
- Move the composable call into the setup function of a component that lives within the table's slot tree.
Example fix
// before — useExpanded() called in a standalone component with no table ancestor
const { expanded } = useExpanded()
// after — only call inside a VDataTable slot descendant, or provide it yourself:
import { createExpanded, VDataTableExpandedKey } from 'vuetify/components/VDataTable/composables/expand'
// in your custom table setup:
const data = createExpanded(/* props */, /* emit */)
provide(VDataTableExpandedKey, data)
// descendants may now call useExpanded() Defensive patterns
Strategy: type-guard
Validate before calling
// structural check before calling the composable
import { getCurrentInstance } from 'vue'
function canUseExpanded(): boolean {
// only meaningful if a VDataTable ancestor is present; check injection lazily
return !!getCurrentInstance()
} Type guard
import { inject } from 'vue'
import { VDataTableExpandedKey } from 'vuetify/components/VDataTable/composables/expand'
function hasExpandedProvider(): boolean {
return inject(VDataTableExpandedKey, null) != null
} Try / catch
try {
const { expanded } = useExpanded()
} catch (e) {
if (e instanceof Error && e.message === 'foo') {
// not inside a table; fall back to local state
} else throw e
} Prevention
- Keep composables that consume table state inside table slot descendants only.
- When extracting table internals, also re-provide the symbols you consume.
- Maintain a single Vuetify install to keep Symbol.for keys identical.
When it happens
Trigger: Calling useExpanded() outside of a VDataTable/VDataTableServer/VDataTableVirtual (or a component that called createExpanded). Typically hit by slot/slot-prop consumers or by exporting a child composable from a wrapper component that is rendered without the table provider.
Common situations: Using the table's internal composables in a custom standalone component, rendering a cell slot outside the table's provide scope, or upgrading Vuetify where the data-table was refactored to injection-key-based composables (Vuetify 3 / Labs).
Related errors
AI-assisted analysis of vuetifyjs/vuetify@8d153908df (2026-08-12).
Data as JSON: /api/errors/fc15051254b4d4d0.
Report an issue: GitHub.