hasura/graphql-engine · error

failed to obtain plugin archive: %w

Error message

failed to obtain plugin archive: %w

What it means

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'.

Source

Thrown at cli/plugins/download/downloader.go:40

	stderrors "errors"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"

	"github.com/hasura/graphql-engine/cli/v2/internal/errors"
)

// download gets a file from the internet in memory and writes it content
// to a Verifier.
func download(url string, verifier Verifier, fetcher Fetcher) (io.ReaderAt, int64, error) {
	var op errors.Op = "download.download"

	body, err := fetcher.Get(url)
	if err != nil {
		return nil, 0, errors.E(op, fmt.Errorf("failed to obtain plugin archive: %w", err))
	}
	defer body.Close()

	data, err := io.ReadAll(io.TeeReader(body, verifier))
	if err != nil {
		return nil, 0, errors.E(op, fmt.Errorf("could not read archive: %w", err))
	}

	err = verifier.Verify()
	if err != nil {
		return bytes.NewReader(data), int64(len(data)), errors.E(op, err)
	}

	return bytes.NewReader(data), int64(len(data)), nil
}

// extractZIP extracts a zip file into the target directory.
func extractZIP(targetDir, fileName string, read io.ReaderAt, size int64) error {

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Verify the plugin download URL is correct and reachable (curl -fL <url>).
  2. Check network egress: DNS, proxy env vars (HTTP_PROXY/HTTPS_PROXY), and firewall rules from the machine/CI runner.
  3. If behind a TLS-intercepting proxy, install the required CA cert or configure the Fetcher's HTTP client with the corporate root CA.
  4. Retry — transient network failures are a common cause; implement retry with backoff in the Fetcher.

Example fix

// before
body, err := http.Get(pluginURL) // fails with TLS/proxy errors

// after
client := &http.Client{Timeout: 30 * time.Second}
body, err := client.Get(pluginURL)
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight reachability check before calling Get
if resp, err := http.Head(pluginURL); err != nil || resp.StatusCode >= 400 {
    return fmt.Errorf("plugin host unreachable: %v", err)
}

Try / catch

var derr error
for i := 0; i < 3; i++ {
    if _, err := downloader.Get(...); err == nil { break }
    derr = err
    time.Sleep(time.Duration(i+1) * time.Second)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/1215f515e32aa1ab. Report an issue: GitHub.