TanStack/table · warning

aggregationFn at index ${i} for column '${column.id}' needs

Error message

aggregationFn at index ${i} for column '${column.id}' needs a stable id

What it means

When `columnDef.aggregationFn` is an array, each element must be resolvable to a stable id: either a plain string (used as both ref and id) or an object descriptor carrying `id` and `aggregationFn`. Bare function values or malformed objects have no id, so this warning fires and the entry is resolved as `{ aggregationFn: undefined, id: undefined }` — it is skipped in the keyed aggregation result. The id is required so aggregated results can be keyed and merged across grouped sub-rows.

Source

Thrown at packages/table-core/src/features/row-aggregation/rowAggregationFeature.utils.ts:300

        : isAggregationFnDescriptor(item)
          ? item.id
          : undefined
    if (id !== undefined) ids[id] = (ids[id] ?? 0) + 1
  }

  const resolved: Array<ResolvedAggregationFn<TFeatures, TData>> = []

  for (let i = 0; i < option.length; i++) {
    const item = option[i]
    const id =
      typeof item === 'string'
        ? item
        : isAggregationFnDescriptor(item)
          ? item.id
          : undefined

    if (id === undefined) {
      warn(
        `aggregationFn at index ${i} for column '${column.id}' needs a stable id`,
      )
      resolved.push({ aggregationFn: undefined, id: undefined })
      continue
    }

    if (ids[id]! > 1) {
      warn(`aggregationFn id '${id}' for column '${column.id}' is duplicated`)
      resolved.push({ aggregationFn: undefined, id })
      continue
    }

    const ref = isAggregationFnDescriptor(item) ? item.aggregationFn : item
    resolved.push({
      aggregationFn: resolveAggregationFn(column, ref),
      id,
    })
  }

View on GitHub (pinned to d01c01bedb)

Solutions

  1. Wrap each bare function in a descriptor with an explicit id: `{ id: 'sum', aggregationFn: myFn }`.
  2. Or use plain strings referencing registered fns: `aggregationFn: ['sum', 'mean']`.
  3. Check each array element for a literal `id` property; fix typos like `key` or `name`.
  4. Verify the multiple-aggregation result shape: entries without ids never appear in the keyed object, so add ids to see their values.
  5. Strengthen types (drop `as any`) so the compiler enforces the `AggregationFnDescriptor` shape.

Example fix

// before
aggregationFn: [sumFn, meanFn]

// after
aggregationFn: [
  { id: 'sum', aggregationFn: sumFn },
  { id: 'mean', aggregationFn: meanFn },
]
Defensive patterns

Strategy: validation

Validate before calling

function assertStableIds(option: unknown) {
  if (!Array.isArray(option)) return
  option.forEach((item, i) => {
    const ok =
      typeof item === 'string' ||
      (!!item && typeof item === 'object' && typeof (item as any).id === 'string')
    if (!ok) throw new Error(`aggregationFn[${i}] must be a string or { id, aggregationFn }`)
  })
}
assertStableIds(columnDef.aggregationFn)

Type guard

function isAggregationFnDescriptor(
  value: unknown,
): value is { id: string; aggregationFn: unknown } {
  return (
    !!value &&
    typeof value === 'object' &&
    typeof (value as any).id === 'string' &&
    'aggregationFn' in (value as any)
  )
}

Try / catch

try {
  const entries = column.getAggregationFns()
  const missing = entries.filter((e) => e.id === undefined)
  if (missing.length) {
    console.warn(`${missing.length} aggregation entries skipped for lack of a stable id`)
  }
} catch (e) {
  console.error('failed to resolve aggregation entries', e)
}

Prevention

When it happens

Trigger: Passing `aggregationFn: [myFn, otherFn]` (bare functions, no wrapping descriptor); passing an object with only `aggregationFn` but no `id` key (or misspelled `id`); passing a non-string, non-descriptor value like a number inside the array.

Common situations: Migrating from a scalar `aggregationFn` to multiple aggregations and assuming plain functions work in arrays; building descriptors dynamically and omitting `id`; TypeScript's looser typing letting an object missing `id` slip through with `as any`.

Related errors


AI-assisted analysis of TanStack/table@d01c01bedb (2026-08-28). Data as JSON: /api/errors/3a32f5f8fad2e6bb. Report an issue: GitHub.