{"record":{"id":"282288b8309bc60b","repo":"kubernetes/kops","slug":"error-finding-contained-version","errorCode":null,"errorMessage":"error finding contained version","messagePattern":"error finding contained version","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nodeup/pkg/model/containerd.go","lineNumber":162,"sourceCode":"\t}\n\tfor _, v := range f {\n\t\tfileTask := &nodetasks.File{\n\t\t\tPath:     \"/usr/sbin/runc\",\n\t\t\tContents: v,\n\t\t\tType:     nodetasks.FileType_File,\n\t\t\tMode:     new(\"0755\"),\n\t\t}\n\t\tc.AddTask(fileTask)\n\t}\n\n\t// Add configuration file for easier use of crictl\n\tb.addCrictlConfig(c)\n\n\tvar containerdVersion string\n\tif b.NodeupConfig.ContainerdConfig != nil {\n\t\tcontainerdVersion = fi.ValueOf(b.NodeupConfig.ContainerdConfig.Version)\n\t} else {\n\t\treturn fmt.Errorf(\"error finding contained version\")\n\t}\n\tsv, err := semver.ParseTolerant(containerdVersion)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing container runtime version %q: %w\", containerdVersion, err)\n\t}\n\tc.AddTask(b.buildSystemdService(sv))\n\n\tif err := b.buildSysconfigFile(c); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (b *ContainerdBuilder) buildSystemdService(containerdVersion semver.Version) *nodetasks.Service {\n\t// Based on https://github.com/containerd/containerd/blob/master/containerd.service\n\n\tmanifest := &systemd.Manifest{}","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/nodeup/pkg/model/containerd.go#L144-L180","documentation":"After installing binaries, installContainerd reads the containerd version from NodeupConfig.ContainerdConfig.Version to build the systemd service. If NodeupConfig.ContainerdConfig is nil (no containerd config was rendered into the nodeup config), there is no version to use, and nodeup returns this typo'd error ('contained' instead of 'containerd') at nodeup/pkg/model/containerd.go:162.","triggerScenarios":"The nodeup bootstrap configuration for the node contains no ContainerdConfig stanza even though nodeup decided to install containerd — e.g. cluster spec updated by a different kOps version, or a hand-edited/stale nodeup config where the containerd block was dropped.","commonSituations":"Stale nodeup config on an existing instance after a kOps upgrade changed the config schema, running nodeup manually with an old --config file, or custom builder paths where containerd installation is forced without its config block.","solutions":["Regenerate the cluster config with `kops update cluster` so nodes receive a nodeup config containing spec.containerd (ContainerdConfig)","Verify spec.containerd.version is set in the cluster manifest and re-run the rolling update","Re-fetch the latest nodeup config for the instance (kops get cluster --full / restart the kOps-generated cloud-init so nodeup pulls the current config)","If running nodeup by hand, pass the current nodeup config produced by the same kOps version"],"exampleFix":"# before (cluster.yaml, no containerd block)\nspec: {}\n# after\nspec:\n  containerd:\n    version: 1.7.18","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := b.installContainerd(c); err != nil {\n    if strings.Contains(err.Error(), \"error finding contained version\") {\n        return fmt.Errorf(\"nodeup config missing ContainerdConfig; regenerate with 'kops update cluster': %w\", err)\n    }\n    return err\n}","preventionTips":["Keep cluster spec and nodeup config generated by the same kOps version"],"tags":["nodeup","containerd","config"],"backgroundTag":"missing-config-field","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}