{"record":{"id":"9dcd52d6e3e5c914","repo":"kubernetes/kops","slug":"unable-to-parse-version-string-q","errorCode":null,"errorMessage":"unable to parse version string: %q","messagePattern":"unable to parse version string: %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/nodemodel/wellknownassets/containerd.go","lineNumber":76,"sourceCode":"\t\tversion := fi.ValueOf(containerd.Version)\n\t\tif version == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"unable to find containerd version\")\n\t\t}\n\n\t\tassetURL, err := findContainerdVersionUrl(arch, version)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tcanonicalURL = assetURL.String()\n\t}\n\n\treturn buildFileAsset(assetBuilder, canonicalURL, knownHash)\n}\n\nfunc findContainerdVersionUrl(arch architectures.Architecture, version string) (*url.URL, error) {\n\tsv, err := semver.ParseTolerant(version)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to parse version string: %q\", version)\n\t}\n\tif sv.LT(semver.MustParse(\"2.1.0\")) {\n\t\treturn nil, fmt.Errorf(\"unsupported legacy containerd version: %q\", version)\n\t}\n\n\tvar u string\n\tswitch arch {\n\tcase architectures.ArchitectureAmd64:\n\t\tu = fmt.Sprintf(containerdReleaseUrlAmd64, version, version)\n\tcase architectures.ArchitectureArm64:\n\t\tu = fmt.Sprintf(containerdReleaseUrlArm64, version, version)\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"unknown arch: %q\", arch)\n\t}\n\n\treturn url.Parse(u)\n}\n","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/nodemodel/wellknownassets/containerd.go#L58-L94","documentation":"findContainerdVersionUrl parses the containerd version with semver.ParseTolerant before constructing the GitHub release URL. If the string is not a tolerable semantic version (missing numbers, garbage characters), the parse fails and this error is returned wrapping the raw version. It blocks building a release URL from an unusable version.","triggerScenarios":"FindContainerdAsset falls back to version-based URL building with containerd.Version values like 'latest', 'v2.', '2.1', 'containerd-2.1.0', or any non-semver string.","commonSituations":"Users set version to a tag-style or marketing string instead of a release number; copy-paste of the full tarball filename into the version field; shell/templating substituting empty or partial values.","solutions":["Set containerd.version to a clean semver value such as '2.1.0' (the 'v' prefix is tolerated)","Strip any filename/suffix from the configured version so only 'X.Y.Z' remains","Pin to a known containerd release listed on the containerd GitHub releases page"],"exampleFix":"// before\ncontainerd:\n  version: containerd-2.1.0-linux-amd64\n// after\ncontainerd:\n  version: \"2.1.0\"","handlingStrategy":"validation","validationCode":"if _, err := semver.ParseTolerant(containerdVersion); err != nil {\n    return fmt.Errorf(\"containerd.version %q is not a valid semver: %v\", containerdVersion, err)\n}","typeGuard":null,"tryCatchPattern":"asset, err := wellknownassets.FindContainerdAsset(ig, assetBuilder, arch)\nif err != nil && strings.Contains(err.Error(), \"unable to parse version string\") {\n    return fmt.Errorf(\"containerd.version must look like X.Y.Z: %w\", err)\n}","preventionTips":["Store containerd version as a bare semver string, never a filename or tag","Strip any leading/trailing whitespace when templating the version","Add a semver regex check to your manifest lint pipeline"],"tags":["containerd","semver","version-parsing"],"backgroundTag":"invalid-semver-version","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}