{"record":{"id":"e0f007912c670197","repo":"kubernetes/kops","slug":"found-multiple-matches-for-asset-q","errorCode":null,"errorMessage":"found multiple matches for asset %q","messagePattern":"found multiple matches for asset %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/assets/assetdata/data.go","lineNumber":72,"sourceCode":"\t\t\treturn fmt.Errorf(\"parsing embedded file %q: %w\", p, err)\n\t\t}\n\n\t\tmatches := manifest.Matches(canonicalURL.String())\n\t\tallMatches = append(allMatches, matches...)\n\t\treturn nil\n\t}); err != nil {\n\t\treturn nil, false, fmt.Errorf(\"walking embedded data: %w\", err)\n\t}\n\n\thashes := sets.New[string]()\n\tfor _, match := range allMatches {\n\t\thashes.Insert(match.SHA256)\n\t}\n\tif len(hashes) == 0 {\n\t\treturn nil, false, nil\n\t}\n\tif len(hashes) > 1 {\n\t\treturn nil, false, fmt.Errorf(\"found multiple matches for asset %q\", canonicalURL)\n\t}\n\th, err := hashing.FromString(hashes.UnsortedList()[0])\n\tif err != nil {\n\t\treturn nil, false, err\n\t}\n\treturn h, true, nil\n}\n\ntype file struct {\n\tName   string `json:\"name,omitempty\"`\n\tSHA256 string `json:\"sha256,omitempty\"`\n}\n\ntype fileStore struct {\n\tBase string `json:\"base,omitempty\"`\n}\n\ntype manifest struct {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/assets/assetdata/data.go#L54-L90","documentation":"GetHash collects SHA256 hashes of all manifest entries whose filestore base + relative name matches the requested canonicalURL. If more than one distinct hash is found, it refuses to guess and returns this error, signaling ambiguous or conflicting asset data.","triggerScenarios":"Calling assetdata.GetHash for a URL that matches entries in multiple embedded manifests, or duplicate files entries with different sha256 values under overlapping filestores whose Base values are prefixes of the URL.","commonSituations":"Two manifest YAMLs regenerated for different Kubernetes versions both cover the same filestore path; duplicate filestore bases (one a prefix of another) with divergent hashes; hand-edited manifests reintroducing stale entries.","solutions":["Search the embedded *.yaml manifests for the URL/path and remove the stale or wrong entry so only one hash remains","Ensure each manifest's filestores base is unique (no overlapping prefix bases for the same files)","Regenerate conflicting manifests with tools/cmd/generatefileassets from authoritative SHA256SUMS","Pin the asset URL to a path only covered by one manifest"],"exampleFix":"// before: two manifests both list the path with different hashes\n// filestore base https://foo/bar in a.yaml and https://foo in b.yaml\n// after: keep one authoritative manifest, delete or scope the other base\nfilestores:\n- base: https://foo/bar   # only a.yaml\n","handlingStrategy":"try-catch","validationCode":"// before lookup, ensure the URL is scoped to one filestore\nurls := []string{assetURL}\nfor _, u := range urls {\n\tvar hits int\n\tfor _, base := range knownFilestoreBases {\n\t\tif strings.HasPrefix(u, base) { hits++ }\n\t}\n\tif hits > 1 { /* ambiguous URL: narrow it before calling GetHash */ }\n}","typeGuard":null,"tryCatchPattern":"h, found, err := assetdata.GetHash(u)\nif err != nil && strings.Contains(err.Error(), \"found multiple matches\") {\n\t// pick an explicit single-source manifest or fix the duplicate entry upstream\n\treturn err\n}","preventionTips":["Keep one authoritative manifest per filestore base; avoid prefix-overlapping bases","Deduplicate file entries when regenerating manifests","Pin asset URLs to paths covered by exactly one manifest","Add a test asserting every well-known URL yields at most one hash"],"tags":["asset-resolution","ambiguity","hash"],"backgroundTag":"ambiguous-asset-hash","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"}