jeessy2/ddns-go · error

%w zip 文件: %v

Error message

%w zip 文件: %v

What it means

unzip must buffer the whole source into memory because zip decompression requires the file size; if io.ReadAll of the HTTP response (or other reader) fails, it returns errCannotDecompressFile wrapped with this message. The %w wrapping preserves the sentinel for errors.Is checks.

Source

Thrown at util/update/decompress.go:45

// 可能返回以下封装过的错误:
//   - errCannotDecompressFile
//   - errExecutableNotFoundInArchive
func decompressCommand(src io.Reader, url, cmd string) (io.Reader, error) {
	for ext, decompress := range fileTypes {
		if strings.HasSuffix(url, ext) {
			return decompress(src, cmd)
		}
	}
	log.Print("It's not a compressed file, skip decompressing")
	return src, nil
}

func unzip(src io.Reader, cmd string) (io.Reader, error) {
	// 解压 Zip 格式时需要文件大小。
	// 因此我们需要先将 HTTP 响应读取到缓冲区中。
	buf, err := io.ReadAll(src)
	if err != nil {
		return nil, fmt.Errorf("%w zip 文件: %v", errCannotDecompressFile, err)
	}

	r := bytes.NewReader(buf)
	z, err := zip.NewReader(r, r.Size())
	if err != nil {
		return nil, fmt.Errorf("%w zip 文件: %s", errCannotDecompressFile, err)
	}

	for _, file := range z.File {
		_, name := filepath.Split(file.Name)
		if !file.FileInfo().IsDir() && matchExecutableName(cmd, name) {
			return file.Open()
		}
	}

	return nil, fmt.Errorf("在 zip 文件中%w:%q", errExecutableNotFoundInArchive, cmd)
}

View on GitHub (pinned to 5874c2e666)

Solutions

  1. Check network connectivity and retry the update command
  2. Verify the download URL is reachable and the server keeps the connection open for large files
  3. Retry with a more stable connection or smaller/resumable download; use errors.Is(err, errCannotDecompressFile) to confirm this family
Defensive patterns

Strategy: retry

Validate before calling

// Verify the download source is reachable before streaming
resp, err := http.Get(archiveURL)
if err != nil {
    return fmt.Errorf("archive unreachable: %w", err)
}
defer resp.Body.Close()
if resp.ContentLength == 0 {
    return fmt.Errorf("archive is empty")
}

Try / catch

r, err := unzip(src, cmd)
if err != nil {
    if errors.Is(err, errCannotDecompressFile) {
        // transient read failure: retry download with backoff
        return retryDownload(archiveURL, cmd)
    }
    return err
}

Prevention

When it happens

Trigger: Calling the update/self-update flow that downloads an archive and unzips it, when reading the response stream fails mid-download — network drop, connection reset, timeout, or a reader error on the underlying stream.

Common situations: Unstable network during self-update; proxy or firewall cutting long downloads; server closing connection early; running behind flaky VPN.

Related errors


AI-assisted analysis of jeessy2/ddns-go@5874c2e666 (2026-09-03). Data as JSON: /api/errors/2237d4f2100ab833. Report an issue: GitHub.