multica-ai/multica · error

gzip reader: %w

Error message

gzip reader: %w

What it means

extractBinaryFromTarGz wraps the archive in gzip.NewReader first; failure returns 'gzip reader: %w' (flate.CorruptInputError or ErrHeader). Note the SHA-256 was verified against the manifest before extraction, so reaching this error with a valid checksum usually means the asset is not actually gzip data despite its name — a packaging bug rather than a corrupted transfer.

Source

Thrown at server/internal/cli/update.go:486

		return "", fmt.Errorf("chmod temp file: %w", err)
	}

	// Replace the original binary. On Windows this moves the running executable
	// aside first; on Unix a plain rename over the running inode is fine.
	if err := replaceBinary(tmpPath, exePath); err != nil {
		os.Remove(tmpPath)
		return "", fmt.Errorf("replace binary: %w", err)
	}

	return fmt.Sprintf("Downloaded %s and replaced %s", assetName, exePath), nil
}

// extractBinaryFromTarGz reads a .tar.gz stream and returns the contents of the
// named file entry.
func extractBinaryFromTarGz(r io.Reader, name string) ([]byte, error) {
	gz, err := gzip.NewReader(r)
	if err != nil {
		return nil, fmt.Errorf("gzip reader: %w", err)
	}
	defer gz.Close()

	tr := tar.NewReader(gz)
	for {
		hdr, err := tr.Next()
		if err == io.EOF {
			return nil, fmt.Errorf("binary %q not found in archive", name)
		}
		if err != nil {
			return nil, fmt.Errorf("read tar: %w", err)
		}
		// Match the binary name (may be prefixed with a directory).
		if filepath.Base(hdr.Name) == name && hdr.Typeflag == tar.TypeReg {
			data, err := io.ReadAll(tr)
			if err != nil {
				return nil, fmt.Errorf("read binary: %w", err)
			}

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Inspect the asset: `file multica_*.tar.gz` — it reports the real format.
  2. Fix the release pipeline so the compression matches the file extension expected by the updater.
  3. Re-release with consistent packaging, then retry the update.
  4. If a custom format is intentional, extend the extractor to handle it and update asset naming.

Example fix

null
Defensive patterns

Strategy: validation

Validate before calling

// sniff magic bytes before extraction
head := make([]byte, 2)
if _, err := io.ReadFull(bytes.NewReader(archiveData), head); err == nil {
    if !(head[0] == 0x1f && head[1] == 0x8b) {
        // not gzip despite .tar.gz name: reject before gzip.NewReader
    }
}

Type guard

func isGzip(data []byte) bool {
    return len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b
}

Try / catch

data, err := extractBinaryFromTarGz(r, "multica")
if err != nil && strings.HasPrefix(err.Error(), "gzip reader") {
    // packaging mismatch: asset is not gzip; check `file` on the downloaded artifact
}

Prevention

When it happens

Trigger: A non-Windows asset uploaded as plain tar, zip, or compressed with another algorithm (zstd) while named .tar.gz; a release pipeline change in the compression config; a checksum manifest computed over the wrong file so a different-format archive passes verification.

Common situations: GoReleaser config edits (e.g. switching to zstd or disabling compression) without updating the extension logic in releaseArchiveExtension; manually re-packaged release assets that kept the old filename.

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/4a2ad39adab55b0d. Report an issue: GitHub.