What happened
Every pulumi preview/up that constructs an eks.Cluster fails during Construct with:
error: <pkg>:index:<Component> resource 'my-cluster' has a problem: Invalid version. Must be a string. Got type "object".
error: Error: failed to register new resource my-cluster [...]: 2 UNKNOWN: resource monitor shut down
Stack trace (obtained by patching semver's thrown message, see below):
at new SemVer (node_modules/semver/classes/semver.js:21:97)
at compare (node_modules/semver/functions/compare.js:5:3)
at Object.lt (node_modules/semver/functions/lt.js:4:29)
at assertCompatibleKubectlVersionExists (node_modules/@pulumi/eks/dependencies.js:45)
at createCore (node_modules/@pulumi/eks/cluster.js:408)
at createCluster (node_modules/@pulumi/eks/cluster.js:1916)
at new Cluster (node_modules/@pulumi/eks/cluster.js:1802)
Root cause
nodejs/eks/dependencies.ts, assertCompatibleKubectlVersionExists:
const kcVersion = semver.clean(kctlVersion.clientVersion.gitVersion, { loose: true });
if (semver.lt(kcVersion, minKubectlVersion)) {
semver.clean() returns null for any input it cannot parse — it does not throw. That null is
passed unguarded into semver.lt(), which calls new SemVer(null) and throws
TypeError: Invalid version. Must be a string. Got type "object".
The message is actively misleading: the value is null, not an object. It only says "object"
because typeof null === "object". Anyone reading it reasonably concludes some object is being
passed where a version string belongs, and goes looking through Pulumi's provider/plugin version
plumbing — which is nowhere near the actual problem.
How to reproduce
Any kubectl whose gitVersion is not semver-cleanable. A build without version stamping is the
common case:
$ kubectl version --client=true --output=json
{
"clientVersion": {
"major": "",
"minor": "",
"gitVersion": "v0.0.0-master+$Format:%H$",
...
}
}
> semver.clean("v0.0.0-master+$Format:%H$", { loose: true })
null
> semver.lt(null, "1.24.0")
TypeError: Invalid version. Must be a string. Got type "object".
We hit this on the public.ecr.aws/pulumi/pulumi:3.256.0 image used by Pulumi Deployments, whose
/usr/bin/kubectl is an unstamped build (filed separately against pulumi-docker-containers). But
the defect here is independent of that image: any unstamped or vendor-patched kubectl triggers it,
and the resulting error gives the user nothing to act on.
Note which.sync("kubectl") succeeds and JSON.parse succeeds, so neither of the two existing
guards fires — the function's own error paths are bypassed and it dies on a raw TypeError instead.
Suggested fix
Guard the null and report the value actually seen:
const gitVersion = kctlVersion.clientVersion?.gitVersion;
const kcVersion = semver.clean(gitVersion ?? "", { loose: true });
if (kcVersion === null) {
throw new Error(
`Could not parse the kubectl version from \`kubectl version --client=true --output=json\`. ` +
`Received gitVersion: ${JSON.stringify(gitVersion)}. ` +
`At least v${minKubectlVersion} of kubectl is required.`,
);
}
if (semver.lt(kcVersion, minKubectlVersion)) { ... }
assertCompatibleAWSCLIExists immediately below has the same shape — semver.clean(version, {loose: true})
feeding semver.major()/semver.lt() with no null check — so it will fail the same way against an
aws --version string it cannot parse. Worth fixing both in one pass.
Environment
@pulumi/eks 2.8.1
@pulumi/pulumi 3.244.0, Pulumi CLI 3.256.0
- Node.js 26.6.0, linux/amd64
What happened
Every
pulumi preview/upthat constructs aneks.Clusterfails duringConstructwith:Stack trace (obtained by patching semver's thrown message, see below):
Root cause
nodejs/eks/dependencies.ts,assertCompatibleKubectlVersionExists:semver.clean()returnsnullfor any input it cannot parse — it does not throw. Thatnullispassed unguarded into
semver.lt(), which callsnew SemVer(null)and throwsTypeError: Invalid version. Must be a string. Got type "object".The message is actively misleading: the value is
null, not an object. It only says"object"because
typeof null === "object". Anyone reading it reasonably concludes some object is beingpassed where a version string belongs, and goes looking through Pulumi's provider/plugin version
plumbing — which is nowhere near the actual problem.
How to reproduce
Any kubectl whose
gitVersionis not semver-cleanable. A build without version stamping is thecommon case:
We hit this on the
public.ecr.aws/pulumi/pulumi:3.256.0image used by Pulumi Deployments, whose/usr/bin/kubectlis an unstamped build (filed separately againstpulumi-docker-containers). Butthe defect here is independent of that image: any unstamped or vendor-patched kubectl triggers it,
and the resulting error gives the user nothing to act on.
Note
which.sync("kubectl")succeeds andJSON.parsesucceeds, so neither of the two existingguards fires — the function's own error paths are bypassed and it dies on a raw TypeError instead.
Suggested fix
Guard the
nulland report the value actually seen:assertCompatibleAWSCLIExistsimmediately below has the same shape —semver.clean(version, {loose: true})feeding
semver.major()/semver.lt()with no null check — so it will fail the same way against anaws --versionstring it cannot parse. Worth fixing both in one pass.Environment
@pulumi/eks2.8.1@pulumi/pulumi3.244.0, Pulumi CLI 3.256.0