{"record":{"id":"2013c608060b7a5a","repo":"kubernetes/kops","slug":"unable-to-parse-asset-url-q-w","errorCode":null,"errorMessage":"unable to parse asset URL %q: %w","messagePattern":"unable to parse asset URL %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/nodemodel/wellknownassets/containerd.go","lineNumber":98,"sourceCode":"\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\nfunc buildFileAsset(assetBuilder *assets.AssetBuilder, canonicalURL string, knownHashString string) (*assets.FileAsset, error) {\n\tu, err := url.Parse(canonicalURL)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to parse asset URL %q: %w\", canonicalURL, err)\n\t}\n\n\tvar knownHash *hashing.Hash\n\tif knownHashString != \"\" {\n\t\th, err := hashing.FromString(knownHashString)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to parse asset hash %q: %w\", knownHashString, err)\n\t\t}\n\t\tknownHash = h\n\t}\n\n\tasset, err := assetBuilder.RemapFile(u, knownHash)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to remap asset: %w\", err)\n\t}\n\n\treturn asset, nil\n}","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/nodemodel/wellknownassets/containerd.go#L80-L116","documentation":"buildFileAsset parses the canonical containerd-family asset URL with url.Parse before remapping. A malformed canonicalURL (from containerd/nerdctl/runc config) fails here and is wrapped with %w so the underlying parse error is preserved. It is the containerd-package equivalent of the CNI URL parse guard.","triggerScenarios":"FindContainerdAsset, FindNerdctlAsset, or FindRuncAsset pass a canonicalURL (often built from containerd.packages or custom URL settings) that url.Parse rejects — e.g. containing spaces, control characters, or a scheme-less malformed string.","commonSituations":"Custom package URLs in the cluster spec with typos or unencoded spaces; template expansion errors producing empty/garbled URLs; pasting URLs with surrounding quotes or trailing punctuation.","solutions":["Inspect the wrapped error for the exact position/syntax problem and correct the canonical URL in the cluster spec","URL-encode special characters (spaces -> %20) in configured asset URLs","Validate the configured URL with url.Parse or a validator before applying the cluster spec","If using containerd.packages, point the URL fields at valid https tarball URLs"],"exampleFix":"// before\nurl: \"https://github.com/containerd/containerd/releases/download/v2.1.0/containerd 2.1.0.tar.gz\"\n// after\nurl: \"https://github.com/containerd/containerd/releases/download/v2.1.0/containerd-2.1.0-linux-amd64.tar.gz\"","handlingStrategy":"validation","validationCode":"if _, err := url.Parse(canonicalURL); err != nil {\n    return fmt.Errorf(\"containerd asset URL %q is invalid: %v\", canonicalURL, err)\n}","typeGuard":null,"tryCatchPattern":"asset, err := wellknownassets.FindContainerdAsset(ig, assetBuilder, arch)\nif err != nil && strings.Contains(err.Error(), \"unable to parse asset URL\") {\n    return fmt.Errorf(\"fix the configured containerd asset URL: %w\", err)\n}","preventionTips":["URL-encode special characters in configured asset URLs","Validate all package URLs with url.Parse during manifest lint","Copy URLs programmatically rather than by hand to avoid stray characters"],"tags":["url-parsing","containerd","asset"],"backgroundTag":"invalid-asset-url","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"}