facebook/react · error · Error

Unsupported node type: ${node.type}

Error message

Unsupported node type: ${node.type}

What it means

This is the catch-all of analyzePropertyChain in exhaustive-deps. The function only knows how to turn Identifiers and non-computed MemberExpression/OptionalMemberExpression chains into dotted paths; any other node type - computed member access, calls, binary expressions, template literals - cannot become a property chain and hits the final throw with the node's type name. So a dependency entry whose root shape is not a plain dotted reference crashes the rule.

Source

Thrown at packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts:1966

    markNode(node, optionalChains, result);
    return result;
  } else if (
    node.type === 'ChainExpression' &&
    (!('computed' in node) || !node.computed)
  ) {
    const expression = node.expression;

    if (expression.type === 'CallExpression') {
      throw new Error(`Unsupported node type: ${expression.type}`);
    }

    const object = analyzePropertyChain(expression.object, optionalChains);
    const property = analyzePropertyChain(expression.property, null);
    const result = `${object}.${property}`;
    markNode(expression, optionalChains, result);
    return result;
  } else {
    throw new Error(`Unsupported node type: ${node.type}`);
  }
}

function getNodeWithoutReactNamespace(
  node: Expression | Super,
): Expression | Identifier | Super {
  if (
    node.type === 'MemberExpression' &&
    node.object.type === 'Identifier' &&
    node.object.name === 'React' &&
    node.property.type === 'Identifier' &&
    !node.computed
  ) {
    return node.property;
  }
  return node;
}

View on GitHub (pinned to eafeac097b)

Solutions

  1. Replace the offending entry with a reference the rule understands: depend on the array/object (items) or the function (fn), not an indexed or called result
  2. Hoist the computed value into a stable variable (const first = items[0]) before the hook and depend on the variable
  3. Update eslint-plugin-react-hooks in case your version predates support for the syntax shape you hit
  4. If the exotic dependency is intentional, inline eslint-disable-next-line react-hooks/exhaustive-deps with a justification comment

Example fix

// before
useMemo(() => items[0]?.trim(), [items[0]]);

// after
const first = items[0];
useMemo(() => first?.trim(), [first]);
Defensive patterns

Strategy: validation

Validate before calling

// Flag non-reference deps entries (computed access, calls, expressions)
// before lint: hook callbacks and their arrays can be checked with a quick parse
// (or simply review for these shapes): items[i], data[key], fn(), a + b
const suspiciousDep = /\[\s*(\w+\s*\[|\w+\s*\(|[^\]a-zA-Z0-9._$\s])/;
if (suspiciousDep.test(depsArraySource)) {
  console.warn('Deps array contains a computed/call/expression entry - hoist it to a variable');
}

Prevention

When it happens

Trigger: A dependency array entry that is a computed access (items[i], data[key]), a direct invocation (fn() or obj.method()), or an arbitrary expression (a + b, `tpl-${x}`) where analyzePropertyChain is asked to analyze the root node. Computed MemberExpression (node.computed === true) and bare CallExpression both fall through every accepting branch into the else-throw.

Common situations: Listing a computed value like items[0] as a dependency instead of items; listing a function call result instead of the function; migrating codebases where deps arrays were written casually; older plugin versions paired with newer parsers.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/a38f2718d7a7fd99. Report an issue: GitHub.