Skip to content

extract-const-value: fold arithmetic BinaryExpression and UnaryExpression#92932

Open
yogeshwaran-c wants to merge 1 commit intovercel:canaryfrom
yogeshwaran-c:fix/revalidate-binary-expression
Open

extract-const-value: fold arithmetic BinaryExpression and UnaryExpression#92932
yogeshwaran-c wants to merge 1 commit intovercel:canaryfrom
yogeshwaran-c:fix/revalidate-binary-expression

Conversation

@yogeshwaran-c
Copy link
Copy Markdown

What?

Make next build recognize compile-time arithmetic in segment-config exports like

export const revalidate = 60 * 5
export const maxDuration = 60 * 60 * 2

Today these fail with

Unsupported node type "BinaryExpression" at "revalidate".
Read More - https://nextjs.org/docs/messages/invalid-page-config

forcing users to inline the result by hand.

Why?

extract-const-value.ts walks the SWC AST of an exported const initializer and folds it down to a runtime value. It already handled literals (null, boolean, string, number, regexp, template literals with no expressions), Array/Object expressions, the undefined identifier, and TS-only wrappers (as, satisfies, type/const assertions). It had no case for BinaryExpression or UnaryExpression, so any compound expression — even a trivially constant one like 60 * 5 or -42 — bailed out as unsupported.

This is reported as #72365, and a few callsites in the wild use the obvious pattern (e.g. 60 * 60 * 24 for a 1-day revalidate window).

How?

Added cases for BinaryExpression and UnaryExpression, restricted to a small set of pure operators with no side-effect or short-circuit semantics:

  • Binary: + - * / % **
  • Unary: - + ~

Logical (&&, ||, ??), comparison (<, >, ==, ===, !=, !==, <=, >=), and unary !, typeof, void, delete are intentionally not added — they either short-circuit (which would change what the extractor sees as "the value") or invoke runtime semantics that don't belong in a build-time constant. They keep returning unsupported.

Recursion handles nesting naturally (60 * 60 * 24 → folds left-to-right; 100 + -42 works because -42 is a UnaryExpression(NumericLiteral(42)) per the SWC AST).

Test plan

Added test/unit/extract-const-value.test.ts with 11 cases:

  • Plain numeric literal (baseline).
  • The exact Next.js 15 - Unsupported "BinaryExpression" error in "revalidate" field for math expressions #72365 regression: 60 * 5.
  • Additive BinaryExpression.
  • Nested binary (60 * 60 * 24).
  • String concat ('edge' + '').
  • Unary -42.
  • Unary inside binary (100 + -42).
  • Exponentiation (2 ** 10).
  • Rejection of && (binary).
  • Rejection of ! (unary).
  • Rejection of 1 + foo — confirms an unfoldable identifier in one operand still propagates the original "Unknown identifier" error rather than getting masked by the new code path.

npx jest test/unit/extract-const-value.test.ts → 11 passed locally.

The test uses the same installBindings() + parseModule setup as the existing parse-page-static-info.test.ts to exercise real SWC parsing.

Fixes #72365

…sion

`export const revalidate = 60 * 5` failed `next build` with

    Unsupported node type "BinaryExpression" at "revalidate"

forcing users to inline the result by hand. The const-value extractor
walked literals, arrays, objects, regexp, template literals, identifiers
(only `undefined`), and TS-only type wrappers — but had no case for
`BinaryExpression` or `UnaryExpression`, so any compile-time arithmetic
or string-concat expression bailed out.

Add cases for `BinaryExpression` and `UnaryExpression` restricted to a
small set of pure operators that have no side-effect or short-circuit
semantics:

- Binary: `+ - * / % **`
- Unary:  `- + ~`

Logical (`&& || ??`), comparison (`< > == ===` etc.), and `!` / `typeof`
/ `void` / `delete` are intentionally left as `unsupported` — they
either short-circuit (changing what we'd extract) or evaluate runtime
semantics that don't belong in a build-time constant.

Added unit tests covering the regression case from vercel#72365 plus
nested folding, string concatenation, unary forms, the exponentiation
operator, and rejection cases for unsupported operators and identifiers
inside an otherwise-foldable expression.

Fixes vercel#72365
@yogeshwaran-c yogeshwaran-c marked this pull request as ready for review April 17, 2026 10:35
@nextjs-bot
Copy link
Copy Markdown
Contributor

Allow CI Workflow Run

  • approve CI run for commit: 6e33f9f

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Next.js 15 - Unsupported "BinaryExpression" error in "revalidate" field for math expressions

2 participants