{"record":{"id":"2893e599784e8d24","repo":"helm/helm","slug":"failed-to-download-plugin-w","errorCode":null,"errorMessage":"failed to download plugin: %w","messagePattern":"failed to download plugin: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/plugin/installer/http_installer.go","lineNumber":174,"sourceCode":"}\n\n// SupportsVerification returns true if the HTTP installer can verify plugins\nfunc (i *HTTPInstaller) SupportsVerification() bool {\n\t// Only support verification for tarball URLs\n\treturn strings.HasSuffix(i.Source, \".tgz\") || strings.HasSuffix(i.Source, \".tar.gz\")\n}\n\n// GetVerificationData returns cached plugin and provenance data for verification\nfunc (i *HTTPInstaller) GetVerificationData() (archiveData, provData []byte, filename string, err error) {\n\tif !i.SupportsVerification() {\n\t\treturn nil, nil, \"\", errors.New(\"verification not supported for this source\")\n\t}\n\n\t// Download plugin data once and cache it\n\tif i.pluginData == nil {\n\t\tdata, err := i.getter.Get(i.Source)\n\t\tif err != nil {\n\t\t\treturn nil, nil, \"\", fmt.Errorf(\"failed to download plugin: %w\", err)\n\t\t}\n\t\ti.pluginData = data.Bytes()\n\t}\n\n\t// Download prov data once and cache it if available\n\tif i.provData == nil {\n\t\tprovData, err := i.getter.Get(i.Source + \".prov\")\n\t\tif err != nil {\n\t\t\t// If provenance file doesn't exist, set provData to nil\n\t\t\t// The verification logic will handle this gracefully\n\t\t\ti.provData = nil\n\t\t} else {\n\t\t\ti.provData = provData.Bytes()\n\t\t}\n\t}\n\n\treturn i.pluginData, i.provData, filepath.Base(i.Source), nil\n}","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/helm/helm/blob/2a29f1770b62844b27197d2507377361d45ad7c0/internal/plugin/installer/http_installer.go#L156-L192","documentation":"Returned by HTTPInstaller.GetVerificationData when getter.Get(i.Source) fails during a --verify install: the HTTP(S) download of the plugin tarball itself failed before provenance data could even be fetched. It wraps a pkg/getter error such as DNS resolution failure, a non-2xx status, TLS certificate error, or proxy refusal. Note this is the verification path; the same download on the plain install path returns the bare getter error.","triggerScenarios":"helm plugin install --verify https://host/myplugin-1.0.0.tgz where the URL returns 404/403/5xx, DNS fails, the TLS cert is untrusted, or an egress proxy blocks the request. Also triggered when the URL only works in a browser because it silently redirects to an auth page.","commonSituations":"CI runners without network egress; plugin artifact moved to a new host but docs still point at the old URL; private hosting that requires auth the getter has no credentials for; self-signed certificates on internal artifact servers.","solutions":["Reproduce outside Helm: curl -fIL <url> to see the actual status code and redirect chain","Fix the URL or re-upload the artifact so the .tgz returns 200 directly","Configure proxy/TLS environment (HTTPS_PROXY, SSL_CERT_FILE) if curl also fails","Retry once for transient 5xx/network errors before treating it as a hard failure"],"exampleFix":"# before\nhelm plugin install --verify https://old.example.com/myplugin-1.0.0.tgz\n# after: confirm reachability first, then install from the live URL\ncurl -fsSI https://cdn.example.com/myplugin-1.0.0.tgz && \\\nhelm plugin install --verify https://cdn.example.com/myplugin-1.0.0.tgz","handlingStrategy":"retry","validationCode":"func reachable(url string) error {\n\tresp, err := http.Head(url)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\tif resp.StatusCode >= 400 {\n\t\treturn fmt.Errorf(\"%s returned %d\", url, resp.StatusCode)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"var err error\nfor attempt := 1; attempt <= 3; attempt++ {\n\t_, err = installer.InstallWithOptions(inst, installer.Options{Verify: true})\n\tif err == nil || !isTransient(err) { // isTransient: unwrap and match net.Error timeouts / 5xx text\n\t\tbreak\n\t}\n\ttime.Sleep(time.Duration(attempt) * time.Second)\n}","preventionTips":["Pre-flight HEAD the tarball URL in CI before helm plugin install --verify","Pin artifact URLs to immutable CDN/release paths rather than mutable 'latest' links","Set HTTPS_PROXY/SSL_CERT_FILE for restricted networks before running Helm"],"tags":["go","helm","plugin","network","http","verification","download"],"backgroundTag":null,"analyzedSha":"2a29f1770b62844b27197d2507377361d45ad7c0","analyzedAt":"2026-08-15T22:02:47.490Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}