{"record":{"id":"5389253b4a832e1d","repo":"facebook/docusaurus","slug":"could-not-extract-apitable-row-name-from-jsx-tree","errorCode":null,"errorMessage":"Could not extract APITable row name from JSX tree:\n${JSON.stringify(node, null, 2)}","messagePattern":"Could not extract APITable row name from JSX tree:\n(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"website/src/components/APITable/index.tsx","lineNumber":34,"sourceCode":"import useBrokenLinks from '@docusaurus/useBrokenLinks';\nimport {useHistory} from '@docusaurus/router';\nimport styles from './styles.module.css';\n\ninterface Props {\n  readonly children: ReactElement<ComponentProps<'table'>>;\n  readonly name?: string;\n}\n\n// ReactNode equivalent of HTMLElement#innerText\nfunction getRowName(node: ReactElement): string {\n  let curNode: ReactNode = node;\n  while (isValidElement(curNode)) {\n    [curNode] = React.Children.toArray(\n      (curNode.props as {children: ReactNode}).children,\n    );\n  }\n  if (typeof curNode !== 'string') {\n    throw new Error(\n      `Could not extract APITable row name from JSX tree:\\n${JSON.stringify(\n        node,\n        null,\n        2,\n      )}`,\n    );\n  }\n  return curNode as string;\n}\n\nfunction APITableRow({\n  name,\n  children,\n  ref,\n}: {\n  name: string | undefined;\n  children: ReactElement<ComponentProps<'tr'>>;\n  ref: React.Ref<HTMLTableRowElement>;","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/facebook/docusaurus/blob/3f483e80e326cc646b54b83d564b3f0c4881b9a6/website/src/components/APITable/index.tsx#L16-L52","documentation":"APITable builds stable anchor IDs by deriving each row's name from its first cell. getRowName walks the first-child chain until it reaches a leaf; if that leaf is not a string (e.g., a component, number, or empty node) it throws and dumps the offending JSX tree. The row's leading cell must contain a text leaf.","triggerScenarios":"A table row whose first <td> begins with a React component (an icon, badge, custom MDX component) instead of text; an empty leading cell; a cell containing only an emoji/image with no text.","commonSituations":"MDX API tables that put an icon or component in the name column; refactoring rows to start with a Type component; cells generated from data where the name field is empty.","solutions":["Ensure the first cell's first leaf is a text string (e.g., put the name text before any icon).","Move non-text leading content to a later column so the leading leaf is text.","If you control the data, guarantee the name field is a non-empty string."],"exampleFix":"// before (MDX)\n| <Icon name=\"foo\"/> foo | description |\n// after\n| foo <Icon name=\"foo\"/> | description |","handlingStrategy":"validation","validationCode":"function assertRowHasTextName(rowChildren: React.ReactNode) {\n  let cur: React.ReactNode = rowChildren;\n  while (React.isValidElement(cur)) {\n    [cur] = React.Children.toArray((cur.props as {children: React.ReactNode}).children);\n  }\n  if (typeof cur !== 'string' || cur.trim() === '') {\n    throw new Error('APITable row first cell must lead with a text name');\n  }\n}","typeGuard":"const rowLeadsWithString = (\n  rowChildren: React.ReactNode,\n): boolean => {\n  let cur: React.ReactNode = rowChildren;\n  while (React.isValidElement(cur)) {\n    [cur] = React.Children.toArray((cur.props as {children: React.ReactNode}).children);\n  }\n  return typeof cur === 'string' && cur.trim() !== '';\n};","tryCatchPattern":null,"preventionTips":["Start each APITable row's name cell with a text leaf, not a component.","Move icons/badges after the leading text in that cell.","For data-driven tables, ensure the name column is a non-empty string."],"tags":["apitable","mdx","react","anchors"],"backgroundTag":null,"analyzedSha":"3f483e80e326cc646b54b83d564b3f0c4881b9a6","analyzedAt":"2026-08-12T13:25:04.382Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}