facebook/react · error · Error
Unsupported node type: ${expression.type}
Error message
Unsupported node type: ${expression.type} What it means
While building the property-chain strings it uses to track stable values, the exhaustive-deps rule walks each dependency expression with analyzePropertyChain. Identifiers and non-computed member/optional-member chains map to strings like 'a.b.c', but a ChainExpression that wraps a CallExpression (an optional call such as foo?.()) has no property-chain representation, so the analysis throws. In practice this means a dependency entry containing an optional function invocation crashes the rule.
Source
Thrown at packages/eslint-plugin-react-hooks/src/rules/ExhaustiveDeps.ts:1957
const object = analyzePropertyChain(node.object, optionalChains);
const property = analyzePropertyChain(node.property, null);
const result = `${object}.${property}`;
markNode(node, optionalChains, result);
return result;
} else if (node.type === 'OptionalMemberExpression' && !node.computed) {
const object = analyzePropertyChain(node.object, optionalChains);
const property = analyzePropertyChain(node.property, null);
const result = `${object}.${property}`;
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' &&View on GitHub (pinned to eafeac097b)
Solutions
- Update eslint-plugin-react-hooks - newer versions handle more optional-chain shapes without crashing
- Depend on the function reference itself and invoke it inside the callback: list props.getValue and call props.getValue?.() in the effect body
- Hoist the result to a variable before the hook if the value is already computed, and depend on that variable
- As a last resort, add // eslint-disable-next-line react-hooks/exhaustive-deps with a comment explaining why the expression cannot be listed
Example fix
// before
useEffect(() => {
props.onReady?.();
}, [props.onReady?.()]);
// after
const onReady = props.onReady;
useEffect(() => {
onReady?.();
}, [onReady]); Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight scan: flag optional calls in dependency arrays before lint runs
// (cheap grep-style check usable in CI or a pre-commit hook)
const optionalCallInDeps = /\[[^\]]*?\?\.[^\]]*?\(/.test(sourceOfHookFile);
if (optionalCallInDeps) {
console.warn('Optional call inside a deps array - rewrite as fn reference + fn?.() in the callback');
} Prevention
- Never list an invocation in the deps array - list the function/value being called
- Call optional functions inside the callback body with fn?.(), depending on fn
- Run lint locally on hook-heavy files before committing
- Upgrade eslint-plugin-react-hooks when adopting newer syntax forms
When it happens
Trigger: A dependency array entry that is an optional call: useEffect(() => {...}, [props.getValue?.()]), useMemo(..., [ref.current?.()]), or chains ending in a call like a?.b.c(). The ChainExpression branch accepts only member-style chains; the CallExpression inside it hits the explicit throw.
Common situations: Codebases using optional chaining heavily; TypeScript strict mode where a function prop is possibly undefined; refactoring that moved an optional invocation from the callback body into the deps array; older plugin versions before optional-chain handling matured.
Related errors
AI-assisted analysis of facebook/react@eafeac097b (2026-08-21).
Data as JSON: /api/errors/e177bc3af8bd1887.
Report an issue: GitHub.