{"record":{"id":"1215f515e32aa1ab","repo":"hasura/graphql-engine","slug":"failed-to-obtain-plugin-archive-w","errorCode":null,"errorMessage":"failed to obtain plugin archive: %w","messagePattern":"failed to obtain plugin archive: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/plugins/download/downloader.go","lineNumber":40,"sourceCode":"\tstderrors \"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/hasura/graphql-engine/cli/v2/internal/errors\"\n)\n\n// download gets a file from the internet in memory and writes it content\n// to a Verifier.\nfunc download(url string, verifier Verifier, fetcher Fetcher) (io.ReaderAt, int64, error) {\n\tvar op errors.Op = \"download.download\"\n\n\tbody, err := fetcher.Get(url)\n\tif err != nil {\n\t\treturn nil, 0, errors.E(op, fmt.Errorf(\"failed to obtain plugin archive: %w\", err))\n\t}\n\tdefer body.Close()\n\n\tdata, err := io.ReadAll(io.TeeReader(body, verifier))\n\tif err != nil {\n\t\treturn nil, 0, errors.E(op, fmt.Errorf(\"could not read archive: %w\", err))\n\t}\n\n\terr = verifier.Verify()\n\tif err != nil {\n\t\treturn bytes.NewReader(data), int64(len(data)), errors.E(op, err)\n\t}\n\n\treturn bytes.NewReader(data), int64(len(data)), nil\n}\n\n// extractZIP extracts a zip file into the target directory.\nfunc extractZIP(targetDir, fileName string, read io.ReaderAt, size int64) error {","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/cli/plugins/download/downloader.go#L22-L58","documentation":"The plugin downloader's fetch stage failed: the injected Fetcher's Get(url) returned an error before any bytes were read. This surfaces network/DNS/TLS/HTTP problems from obtaining the plugin archive and is wrapped under op 'download.download'.","triggerScenarios":"Calling Get (which calls download) with a plugin URL that is unreachable: DNS resolution failure, connection refused, TLS verification error, 4xx/5xx status handled by the Fetcher, a proxy blocking the request, or an air-gapped environment.","commonSituations":"Corporate proxy or firewall blocking the plugin host; mistyped or stale plugin URL; the plugin host is temporarily down; custom CA certificates missing so TLS fails; offline/CI environments without network egress.","solutions":["Verify the plugin download URL is correct and reachable (curl -fL <url>).","Check network egress: DNS, proxy env vars (HTTP_PROXY/HTTPS_PROXY), and firewall rules from the machine/CI runner.","If behind a TLS-intercepting proxy, install the required CA cert or configure the Fetcher's HTTP client with the corporate root CA.","Retry — transient network failures are a common cause; implement retry with backoff in the Fetcher."],"exampleFix":"// before\nbody, err := http.Get(pluginURL) // fails with TLS/proxy errors\n\n// after\nclient := &http.Client{Timeout: 30 * time.Second}\nbody, err := client.Get(pluginURL)","handlingStrategy":"retry","validationCode":"// Pre-flight reachability check before calling Get\nif resp, err := http.Head(pluginURL); err != nil || resp.StatusCode >= 400 {\n    return fmt.Errorf(\"plugin host unreachable: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"var derr error\nfor i := 0; i < 3; i++ {\n    if _, err := downloader.Get(...); err == nil { break }\n    derr = err\n    time.Sleep(time.Duration(i+1) * time.Second)\n}","preventionTips":["Configure HTTP_PROXY/HTTPS_PROXY in corporate networks","Set sane timeouts on the Fetcher's http.Client","Validate plugin URLs against a trusted registry/list before download"],"tags":["network","download","plugin","http"],"backgroundTag":"connection-refused","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}