{"record":{"id":"150d52a97b40272a","repo":"kubernetes/kops","slug":"error-parsing-addon-q-v","errorCode":null,"errorMessage":"error parsing addon %q: %v","messagePattern":"error parsing addon %q: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/clusteraddons/load.go","lineNumber":50,"sourceCode":"\n// LoadClusterAddon loads a set of objects from the specified VFS location\nfunc LoadClusterAddon(vfsContext *vfs.VFSContext, location string) (*ClusterAddon, error) {\n\tu, err := url.Parse(location)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid addon location: %q\", location)\n\t}\n\n\t// TODO: Should we support relative paths for \"standard\" addons?  See equivalent code in LoadChannel\n\n\tresolved := u.String()\n\tklog.V(2).Infof(\"Loading addon from %q\", resolved)\n\taddonBytes, err := vfsContext.ReadFile(resolved)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error reading addon %q: %v\", resolved, err)\n\t}\n\taddon, err := ParseClusterAddon(addonBytes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing addon %q: %v\", resolved, err)\n\t}\n\tklog.V(4).Infof(\"Addon contents: %s\", string(addonBytes))\n\n\treturn addon, nil\n}\n\n// ParseClusterAddon parses a ClusterAddon object\nfunc ParseClusterAddon(raw []byte) (*ClusterAddon, error) {\n\tobjects, err := kubemanifest.LoadObjectsFrom(raw)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error parsing addon %v\", err)\n\t}\n\n\treturn &ClusterAddon{Raw: string(raw), Objects: objects}, nil\n}\n","sourceCodeStart":32,"sourceCodeEnd":66,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/clusteraddons/load.go#L32-L66","documentation":"Once the addon bytes are read, LoadClusterAddon passes them to ParseClusterAddon; a parse failure is re-wrapped with the resolved location. It indicates the fetched file is not a valid set of Kubernetes manifests / addon definition.","triggerScenarios":"LoadClusterAddon fetches content that ParseClusterAddon cannot decode: an HTML error page instead of YAML, truncated download, wrong file, or YAML that fails Kubernetes object decoding.","commonSituations":"S3/proxy returning an error page with HTTP 200; addon URL pointing to an HTML index rather than the manifest; partially uploaded/corrupted addon file in the state store.","solutions":["Inspect the content at the resolved location and confirm it is valid YAML manifests.","Point the addon location to the correct raw manifest file, not an HTML page or index.","Re-upload/re-download the addon file if it was truncated or corrupted."],"exampleFix":"// before\naddon, err := LoadClusterAddon(vfs.Context, \"https://example.com/addons/\") // HTML index\n// after\naddon, err := LoadClusterAddon(vfs.Context, \"https://example.com/addons/rbac-addon.yaml\")","handlingStrategy":"validation","validationCode":"// confirm the location serves YAML, not an HTML page\nbody, err := fetchPreview(resolved)\nif err == nil && (strings.HasPrefix(strings.TrimSpace(string(body)), \"<\") || len(body) == 0) {\n  return fmt.Errorf(\"location %q does not serve a manifest\", resolved)\n}","typeGuard":null,"tryCatchPattern":"addon, err := LoadClusterAddon(vfs.Context, loc)\nif err != nil && strings.Contains(err.Error(), \"error parsing addon\") {\n  return fmt.Errorf(\"location %s does not contain a valid addon manifest; check it points to the raw YAML file\", loc)\n}","preventionTips":["Point addon locations at raw manifest files, never HTML pages or directory indexes.","Validate downloaded addon bytes locally with a YAML parser before use.","Avoid proxies/mirrors that substitute error pages with HTTP 200."],"tags":["clusteraddons","parsing","yaml","manifest"],"backgroundTag":"manifest-parse-failed","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"}