{"record":{"id":"a1c2fd3ed1268a52","repo":"kubernetes/kops","slug":"unable-to-parse-asset-hash-q-w","errorCode":null,"errorMessage":"unable to parse asset hash %q: %w","messagePattern":"unable to parse asset hash %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/nodemodel/wellknownassets/containerd.go","lineNumber":105,"sourceCode":"\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}\n","sourceCodeStart":87,"sourceCodeEnd":117,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/nodemodel/wellknownassets/containerd.go#L87-L117","documentation":"When a known hash string is supplied alongside an asset URL, buildFileAsset converts it with hashing.FromString. If the string is not a recognized hash format (expected like 'sha256:<hex>' or a valid hex digest), this wrapped error is returned. It prevents propagating an unusable hash into the asset builder where it would break integrity verification.","triggerScenarios":"FindContainerdAsset/FindNerdctlAsset/FindRuncAsset are called with knownHashString values that are empty-ish, wrong length, non-hex, or missing the algorithm prefix — e.g. 'abc', 'sha512:...' when only sha256 supported, or a base64 digest.","commonSituations":"Users copy the wrong checksum column; checksum truncated by copy-paste; using a SHA512 sum where a SHA256 is expected; templating substituting an empty value that still passes the != \"\" check as whitespace.","solutions":["Set the hash to the full sha256 hex digest of the asset tarball, e.g. sha256:<64 hex chars>","Recompute the hash: curl -L <url> | sha256sum and use the output","Verify no truncation/whitespace was introduced when pasting the checksum into the spec"],"exampleFix":"// before\nhash: \"e3b0c442\"\n// after\nhash: \"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\"","handlingStrategy":"validation","validationCode":"hex := strings.TrimPrefix(hashString, \"sha256:\")\nif len(hex) != 64 {\n    return fmt.Errorf(\"asset hash must be 64 hex chars (sha256), got %d\", len(hex))\n}\nif _, err := hex.DecodeString(hex); err != nil {\n    return fmt.Errorf(\"asset hash is not valid hex: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"asset, err := wellknownassets.FindContainerdAsset(ig, assetBuilder, arch)\nif err != nil && strings.Contains(err.Error(), \"unable to parse asset hash\") {\n    return fmt.Errorf(\"recompute the sha256 sum of the asset and update the spec: %w\", err)\n}","preventionTips":["Always paste full sha256 hex digests, never truncated values","Recompute checksums when switching to a different containerd release","Keep algorithm prefix consistent with what hashing.FromString expects"],"tags":["containerd","hashing","integrity"],"backgroundTag":"invalid-asset-hash","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"}