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

  1. Only call useExpanded() inside a component that is a descendant of a VDataTable-family component.
  2. If building a custom table, call createExpanded(...) yourself and provide VDataTableExpandedKey before useExpanded().
  3. 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

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.