fix(runtime): bump minimum Node.js version to 22.12.0 (#5370)

* fix(runtime): bump minimum Node.js version to 22.12.0

Aligns the runtime guard with the declared package.json engines requirement.

The Matrix plugin (and potentially others) requires Node >= 22.12.0,
but the runtime guard previously allowed 22.0.0+. This caused confusing
errors like 'Cannot find module @vector-im/matrix-bot-sdk' when the real
issue was an unsupported Node version.

- Update MIN_NODE from 22.0.0 to 22.12.0
- Update error message to reflect the correct version
- Update tests to use 22.12.0 as the minimum valid version

Fixes #5292

* fix: update test versions to match MIN_NODE=22.12.0

---------

Co-authored-by: Markus Glucksberg <markus@glucksberg.com>
This commit is contained in:
Glucksberg
2026-02-05 17:42:52 -04:00
committed by GitHub
parent db8e9b37c6
commit 2ca78a8aed
3 changed files with 20 additions and 12 deletions

View File

@@ -30,7 +30,8 @@ describe("resolvePreferredNodePath", () => {
throw new Error("missing");
});
const execFile = vi.fn().mockResolvedValue({ stdout: "22.1.0\n", stderr: "" });
// Node 22.12.0+ is the minimum required version
const execFile = vi.fn().mockResolvedValue({ stdout: "22.12.0\n", stderr: "" });
const result = await resolvePreferredNodePath({
env: {},
@@ -51,7 +52,8 @@ describe("resolvePreferredNodePath", () => {
throw new Error("missing");
});
const execFile = vi.fn().mockResolvedValue({ stdout: "18.19.0\n", stderr: "" });
// Node 22.11.x is below minimum 22.12.0
const execFile = vi.fn().mockResolvedValue({ stdout: "22.11.0\n", stderr: "" });
const result = await resolvePreferredNodePath({
env: {},
@@ -92,7 +94,8 @@ describe("resolveSystemNodeInfo", () => {
throw new Error("missing");
});
const execFile = vi.fn().mockResolvedValue({ stdout: "22.0.0\n", stderr: "" });
// Node 22.12.0+ is the minimum required version
const execFile = vi.fn().mockResolvedValue({ stdout: "22.12.0\n", stderr: "" });
const result = await resolveSystemNodeInfo({
env: {},
@@ -102,7 +105,7 @@ describe("resolveSystemNodeInfo", () => {
expect(result).toEqual({
path: darwinNode,
version: "22.0.0",
version: "22.12.0",
supported: true,
});
});

View File

@@ -16,13 +16,16 @@ describe("runtime-guard", () => {
});
it("compares versions correctly", () => {
expect(isAtLeast({ major: 22, minor: 0, patch: 0 }, { major: 22, minor: 0, patch: 0 })).toBe(
expect(isAtLeast({ major: 22, minor: 12, patch: 0 }, { major: 22, minor: 12, patch: 0 })).toBe(
true,
);
expect(isAtLeast({ major: 22, minor: 1, patch: 0 }, { major: 22, minor: 0, patch: 0 })).toBe(
expect(isAtLeast({ major: 22, minor: 13, patch: 0 }, { major: 22, minor: 12, patch: 0 })).toBe(
true,
);
expect(isAtLeast({ major: 21, minor: 9, patch: 0 }, { major: 22, minor: 0, patch: 0 })).toBe(
expect(isAtLeast({ major: 22, minor: 11, patch: 0 }, { major: 22, minor: 12, patch: 0 })).toBe(
false,
);
expect(isAtLeast({ major: 21, minor: 9, patch: 0 }, { major: 22, minor: 12, patch: 0 })).toBe(
false,
);
});
@@ -30,11 +33,12 @@ describe("runtime-guard", () => {
it("validates runtime thresholds", () => {
const nodeOk: RuntimeDetails = {
kind: "node",
version: "22.0.0",
version: "22.12.0",
execPath: "/usr/bin/node",
pathEnv: "/usr/bin",
};
const nodeOld: RuntimeDetails = { ...nodeOk, version: "21.9.0" };
const nodeOld: RuntimeDetails = { ...nodeOk, version: "22.11.0" };
const nodeTooOld: RuntimeDetails = { ...nodeOk, version: "21.9.0" };
const unknown: RuntimeDetails = {
kind: "unknown",
version: null,
@@ -43,6 +47,7 @@ describe("runtime-guard", () => {
};
expect(runtimeSatisfies(nodeOk)).toBe(true);
expect(runtimeSatisfies(nodeOld)).toBe(false);
expect(runtimeSatisfies(nodeTooOld)).toBe(false);
expect(runtimeSatisfies(unknown)).toBe(false);
});
@@ -73,7 +78,7 @@ describe("runtime-guard", () => {
const details: RuntimeDetails = {
...detectRuntime(),
kind: "node",
version: "22.0.0",
version: "22.12.0",
execPath: "/usr/bin/node",
};
expect(() => assertSupportedRuntime(runtime, details)).not.toThrow();

View File

@@ -9,7 +9,7 @@ type Semver = {
patch: number;
};
const MIN_NODE: Semver = { major: 22, minor: 0, patch: 0 };
const MIN_NODE: Semver = { major: 22, minor: 12, patch: 0 };
export type RuntimeDetails = {
kind: RuntimeKind;
@@ -88,7 +88,7 @@ export function assertSupportedRuntime(
runtime.error(
[
"openclaw requires Node >=22.0.0.",
"openclaw requires Node >=22.12.0.",
`Detected: ${runtimeLabel} (exec: ${execLabel}).`,
`PATH searched: ${details.pathEnv}`,
"Install Node: https://nodejs.org/en/download",