element-plus/element-plus · error · Error

For nested data item, row-key is required.

Error message

For nested data item, row-key is required.

What it means

When rendering nested (tree) rows, the body renderer computes each child row's key via getRowIdentity(node, rowKey). If a nested data item has no usable identity because row-key is missing or the keyed field is absent on that row, it throws. Tree rendering cannot track expansion/display state without stable keys.

Source

Thrown at packages/components/table/src/table-body/render-helper.ts:257

      const tmp = [rowRender(row, $index, treeRowData ?? undefined)]
      // 渲染嵌套数据
      if (cur) {
        // currentRow 记录的是 index,所以还需主动增加 TreeTable 的 index
        let i = 0
        const traverse = (children: T[], parent: TreeData) => {
          if (!(children && children.length && parent)) return
          children.forEach((node) => {
            // 父节点的 display 状态影响子节点的显示状态
            const innerTreeRowData: Partial<Record<string, any>> = {
              display: parent.display && parent.expanded,
              level: parent.level! + 1,
              expanded: false,
              noLazyChildren: false,
              loading: false,
            }
            const childKey = getRowIdentity(node, rowKey.value)
            if (isPropAbsent(childKey)) {
              throw new Error('For nested data item, row-key is required.')
            }
            cur = { ...treeData.value[childKey] }
            // 对于当前节点,分成有无子节点两种情况。
            // 如果包含子节点的,设置 expanded 属性。
            // 对于它子节点的 display 属性由它本身的 expanded 与 display 共同决定。
            if (cur) {
              innerTreeRowData.expanded = cur.expanded
              // 懒加载的某些节点,level 未知
              cur.level = cur.level || innerTreeRowData.level
              cur.display = !!(cur.expanded && innerTreeRowData.display)
              if (isBoolean(cur.lazy)) {
                if (isBoolean(cur.loaded) && cur.loaded) {
                  innerTreeRowData.noLazyChildren = !(
                    cur.children && cur.children.length
                  )
                }
                innerTreeRowData.loading = cur.loading
              }

View on GitHub (pinned to d357b66546)

Solutions

  1. Add row-key="id" (or equivalent) to el-table when data is nested
  2. Ensure every nested child row has a defined, unique value for the row-key field
  3. Normalize API data to inject ids before assigning to :data

Example fix

// before
<el-table :data="treeRows">
// after
<el-table :data="treeRows" row-key="id">
Defensive patterns

Strategy: validation

Validate before calling

function validateNestedRows(rows: any[], rowKey?: string) {
  if (!rowKey) throw new Error('row-key is required for nested data')
  const walk = (list: any[]) => list.forEach(r => {
    if (r[rowKey] == null) throw new Error(`Row missing row-key field '${rowKey}'`)
    if (Array.isArray(r.children)) walk(r.children)
  })
  walk(rows)
}
validateNestedRows(treeRows, 'id')

Type guard

const hasIdentity = (r: any, k: string): r is { [k: string]: string | number } => r[k] != null

Prevention

When it happens

Trigger: Passing nested data (rows with children arrays) to el-table without row-key prop; row-key pointing to a field that is undefined on some nested child rows; rows whose identity field holds null/undefined values.

Common situations: Tree data from an API where only some levels include the id field; adding children to data after the table was built for flat rows without row-key; row-key bound to a getter-unfriendly field name (case mismatch).

Related errors


AI-assisted analysis of element-plus/element-plus@d357b66546 (2026-08-29). Data as JSON: /api/errors/8c1d344920a32a4f. Report an issue: GitHub.