hasura/graphql-engine · error

could not read archive: %w

Error message

could not read archive: %w

What it means

The archive body was obtained but reading it failed mid-stream: io.ReadAll over an io.TeeReader(body, verifier) returned an error. This means the connection broke, the reader was interrupted, or (most commonly) the Verifier's Write method returned an error while bytes were being tee'd into it.

Source

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

	"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 {
	var op errors.Op = "download.extractZIP"

	zipReader, err := zip.NewReader(read, size)
	if err != nil {
		return errors.E(op, err)
	}

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Inspect the wrapped cause — if it names the Verifier, fix the Verifier's Write path (it must not error during streaming).
  2. Increase the Fetcher's HTTP client timeout / use a longer overall deadline for large archives.
  3. Retry the download; mid-stream resets are frequently transient.
  4. If persistent, download the archive manually with curl to confirm the server delivers the full content-length.

Example fix

// before
body, err := fetcher.Get(url)
data, err := io.ReadAll(io.TeeReader(body, verifier)) // mid-stream failure

// after
client := &http.Client{Timeout: 5 * time.Minute}
body, err := client.Get(url)
data, err := io.ReadAll(io.TeeReader(body, verifier))
Defensive patterns

Strategy: retry

Validate before calling

// Ensure verifier is ready to stream writes before Get
if v, ok := verifier.(interface{ Reset() }); ok { v.Reset() }

Try / catch

if _, err := downloader.Get(...); err != nil && strings.Contains(err.Error(), "could not read archive") {
    // transient: retry with fresh verifier, or surface as network flake
}

Prevention

When it happens

Trigger: Calling Get on a plugin archive when: the HTTP body is cut off mid-transfer (reset connection, content-length mismatch), the Verifier's Write returns an error (e.g. hash verifier still writing after Finalize, or invalid state), or the reader is closed concurrently.

Common situations: Flaky networks truncating downloads in CI; a custom Verifier implementation whose Write errors; server closing keep-alive connections early; timeouts on the http.Client too short for large plugin archives.

Related errors


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