Skip to content

fix: ignore a configured Node version too old to run the frontend build - #25649

Open
totally-not-ai[bot] wants to merge 5 commits into
mainfrom
fix/ignore-too-old-configured-node-version
Open

fix: ignore a configured Node version too old to run the frontend build#25649
totally-not-ai[bot] wants to merge 5 commits into
mainfrom
fix/ignore-too-old-configured-node-version

Conversation

@totally-not-ai

@totally-not-ai totally-not-ai Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Summary

A Node.js version stored in the token file by an old Vaadin version could be installed and used, so the build failed on a version found nowhere in the project. Such a version is now ignored, and a version you configured yourself only gets a warning.

What changed

Behavior change: a node.version read from the token file (flow-build-info.json) that is older than the minimum supported Node.js version (24.0.0) is now dropped instead of used. Affected: only projects whose token file carries such an old version — typically a stale file in the build output folder, or a file packaged into a dependency by mistake. Those projects now fall back to the default Node.js version instead of failing the frontend build. A warning explains where the version came from, how to get rid of it, and how to keep it anyway (set the vaadin.node.version property).

Other changes:

  • NodeResolver now warns when a Node.js version you configured yourself (through node.version or node.folder) is older than the supported minimum. The configured version is still used — only a warning is logged, so nothing breaks for people who chose an old version on purpose.
  • New public constant FrontendUtils.MINIMUM_SUPPORTED_NODE_VERSION. FrontendTools.SUPPORTED_NODE_VERSION now points at it, so the server and the build tools compare against the same floor. The minimum itself is unchanged (24.0); only its text form is now 24.0.0.

Apart from the token-file version being dropped, the change is backward compatible.

API Changes

com.vaadin.flow.internal.FrontendUtils

// Added
public static final FrontendVersion MINIMUM_SUPPORTED_NODE_VERSION // oldest Node.js version the frontend tooling runs on; FrontendTools.SUPPORTED_NODE_VERSION now delegates to it

Test summary

# Status What the test verifies Why it matters
1 A token-file node.version older than the supported minimum is not put into the configuration This is the fix: a stale version must not be installed and used
2 A usable token-file node.version is still passed through The fix must not break normal projects
3 A token-file version that cannot be parsed (e.g. lts) is passed through unchanged Parsing must not silently swallow values the frontend tooling accepts
4 An explicitly configured too-old version is still resolved and used Only a warning is intended here; overriding a deliberate choice would be worse
5 gap A too-old version from node.folder triggers the warning Wrong or missing warning leaves users guessing where the version came from
  • DefaultApplicationConfigurationFactoryTest.create_tokenFileWithOutdatedNodeVersion_versionIsIgnored — rows 1, 2, 3
  • NodeResolverTest.resolve_configuredVersionTooOld_isStillUsedAsConfigured — row 4

Deliberately untested: the exact wording of the log messages, and the node.folder warning path, which needs a real Node installation folder to reach.

The node.version setting is also read from the token file, where an old
Vaadin version may have written a Node version that today's Vite refuses
to run on. Such a version was installed and used as configured, so the
build failed with a version that is found nowhere in the project.
@Artur-

Artur- commented Sep 11, 2026

Copy link
Copy Markdown
Member

It is not clear from the description if this is a behavioral change or not. If the user has explicitly defined a node version to use through a system/Maven/Gradle property, then that should be used and a warning should be printed if the version is incompatible. In this case we should not auto install anything else I think. However, if the wrong version comes from some stale token file, we definitely should use the correct version.

Which of the cases are actually changed here?

@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Test Results

 1 440 files  ±0   1 524 suites  ±0   1h 36m 7s ⏱️ - 1m 20s
12 053 tests +2  11 985 ✅ +2  68 💤 ±0  0 ❌ ±0 
12 371 runs  +2  12 303 ✅ +2  68 💤 ±0  0 ❌ ±0 

Results for commit 5c53bc1. ± Comparison against base commit 1397fea.

♻️ This comment has been updated with latest results.

Overriding a version that somebody has asked for on purpose is worse than
a build that fails for a stated reason, so an explicitly configured Node
version is only warned about. A version in the token file is not chosen
for the project when the file was written by an older Vaadin version, so
one that the frontend tooling cannot run on is ignored instead.
The floor for versions that Vaadin installs by itself is not what the
frontend tooling needs, so a version between it and the supported
minimum was warned about and dropped from the token file even though it
runs. The warning also named the default version as the replacement for
a configured node folder, where a global Node or a configured version is
taken into use instead.
@totally-not-ai

Copy link
Copy Markdown
Contributor Author

@Artur- Good point, and the first version of this did the wrong thing: it overrode any configured version. That is now split by where the version comes from.

Unchanged — an explicitly configured version wins. A version from -Dvaadin.node.version, a Maven/Gradle property or node.folder is used exactly as configured. The only addition is a warning when it is older than the minimum supported version (24.0.0), so the reason for the later failure is stated up front. Nothing is auto-installed in its place.

Changed — a node.version in the token file is ignored when the frontend tooling cannot run on it. The value is checked where the token file is read, so a version older than 24.0.0 is dropped from the configuration parameters and the runtime falls back to the current default. The warning names the file and says to run prepare-frontend, or to set the vaadin.node.version property if that version really is wanted. A version that cannot be parsed is kept, and a globally installed Node is still accepted from 24.0.0 up, as before.

The case this comes from is a project upgraded from Vaadin 24.0, where an IDE-launched dev mode still read "node.version": "v18.14.1" from a flow-build-info.json that Maven no longer rewrites — so Vite failed with a Node version that is nowhere in the project, while mvn package used 24.17.0.

One API addition: FrontendUtils.MINIMUM_SUPPORTED_NODE_VERSION in flow-server, which FrontendTools.SUPPORTED_NODE_VERSION now points to, so the token file check and the frontend tooling share one minimum. Tests cover the token file value being kept when usable, kept when unparseable and ignored when too old, and a configured too-old version still being taken into use.

NodeInstallation.forVersion(alternativeDirFile, nodeVersion));
if (active != null) {
getLogger().debug("Node {} is already installed in {}", nodeVersion,
getLogger().info("Using Node {} from {}", active.nodeVersion(),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not change this to info - most people don't want to see it on every startup

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted to debug — the line only matters when the frontend build misbehaves, so it is not worth one in every startup.

*
* @since 25.4
*/
public static final FrontendVersion MINIMUM_SUPPORTED_NODE_VERSION = new FrontendVersion(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we move this here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Artur- Because the check runs in AbstractConfigurationFactory, which is in flow-server, while FrontendTools is in flow-build-tools — and that module depends on flow-server, not the other way around. Keeping the minimum in flow-server lets both use the same definition: FrontendTools.SUPPORTED_NODE_VERSION now points at it, so there is still one place where the number is written.

The alternative is to check the version in DevModeInitializer, which can see FrontendTools, but it no longer knows that the version came from the token file, so that needs a new flag written into the token file instead — the same amount of API, in a place where a system property can also set the version. Happy to change it if you prefer that split, or to drop the sharing and keep a separate constant in flow-server.

FrontendUtils.MINIMUM_SUPPORTED_NODE_VERSION)) {
getLogger().warn(
"Ignoring Node.js version {} from '{}', as it is older than the minimum supported version {}. "
+ "Run the 'prepare-frontend' goal to rewrite the file, or set the '{}' property to use that version anyway.",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prepare-frontend is deprecated and should not be suggested. Maybe the suggestion should be to clear the target folder instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to suggest clearing the build output folder, so that the file is written again: "The file is out of date, so clear the build output folder to have it written again, or set the 'vaadin.node.version' property to use that version anyway."

The line is of interest only when the frontend build misbehaves, so it
is not worth a line in every startup. Also suggest clearing the build
output folder instead of running a deprecated goal to get rid of an
outdated Node version in the token file.
@github-actions

github-actions Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

📦 Snapshot published

25.4.ignore-too-old-configured-node-version-SNAPSHOT — built from 5c53bc1 (run).

Built without running tests. Look at the checks on this pull request before relying on it.

Every new commit on this branch republishes it while the snapshot build label is there. Add -U to pick the newest build up.

How to use it
<repository>
  <id>vaadin-snapshots</id>
  <url>https://maven.vaadin.com/vaadin-prereleases</url>
  <snapshots><enabled>true</enabled></snapshots>
</repository>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>com.vaadin</groupId>
      <artifactId>flow-bom</artifactId>
      <version>25.4.ignore-too-old-configured-node-version-SNAPSHOT</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

Import flow-bom before vaadin-bom for it to win over the platform's Flow version.

@Artur-

Artur- commented Sep 11, 2026

Copy link
Copy Markdown
Member

Is the potential real root cause here that an add-on packages a flow-build-info.json by mistake and this is read and node version deduced from there? At least in some cases a flow-build-info.json from a jar is excluded but maybe not here?

A token file inside a jar is only read when the project has none of its
own, so it takes a second reading of the classpath to find a dependency
that packages one by mistake. Say so in the warning, as clearing the
build output folder does not help in that case.
@totally-not-ai

Copy link
Copy Markdown
Contributor Author

@Artur- It can be, and the exclusion does apply here — there is only one token file read for every setting, so node.version follows the same lookup as the rest. DefaultApplicationConfigurationFactory.getTokenFileFromClassloader filters out candidates whose path ends with jar!/META-INF/VAADIN/config/flow-build-info.json and uses one only when nothing else is found. So while the project has its own file in the build output folder, a copy packaged into a dependency is never read.

A jar copy is read when the project has none on the classpath: a packaged application, or a run started from a different output folder than the one the build wrote to. If several jars have one, the first is taken and "Unable to fully determine correct flow-build-info" is logged. Worth noting that a production build removes node.version from the token file, so only a dependency packaged from a development build carries one at all.

Either way the source does not change what happens now: the check does not care where the file came from, so a node.version the frontend tooling cannot run on is ignored whether it comes from a stale file in target or from a dependency. The warning now covers both, as clearing the build output folder does not help in the dependency case:

Ignoring Node.js version v18.14.1 from 'META-INF/VAADIN/config/flow-build-info.json', as it is older than the minimum supported version 24.0.0. The file is out of date, so clear the build output folder to have it written again. If the version comes back, the file is packaged into a dependency by mistake. Set the 'vaadin.node.version' property to use the version anyway.

@sonarqubecloud

Copy link
Copy Markdown

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.

1 participant