github/copilot-sdk · error

failed to hash output binary

Error message

failed to hash output binary: %w

What it means

After the CLI binary has been extracted, buildBundle computes its SHA-256 digest with sha256File to record in the bundle manifest. If hashing fails — typically because binaryPath cannot be opened or read — the error is wrapped with this message and bundling stops.

Solutions

  1. Verify the binary exists at the temp path and is readable (ls -l); re-run the bundle.
  2. Exclude the bundler temp/output directories from antivirus real-time scanning if the binary is being quarantined.
  3. Check disk space and filesystem health (dmesg for I/O errors) if reads fail intermittently.
  4. Use a stable temp directory (set TMPDIR) that background cleaners will not purge during the build.

Example fix

// before
# AV quarantines extracted binary during build

// after
# exclude temp dir from AV, then set a fixed TMPDIR
echo "/tmp/bundler-*" >> /etc/clamav/on-access-exclude.conf
TMPDIR=/tmp/bundler-work bundler ...
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(binaryPath)
if err != nil {
	return fmt.Errorf("binary missing at %s: %w", binaryPath, err)
}
if info.Size() == 0 {
	return fmt.Errorf("binary at %s is empty; extraction likely failed", binaryPath)
}

Type guard

func fileReadable(path string) bool {
	f, err := os.Open(path)
	if err != nil {
		return false
	}
	f.Close()
	return true
}

Try / catch

if err := buildBundle(...); err != nil {
	if strings.Contains(err.Error(), "failed to hash output binary") {
		var pe *fs.PathError
		if errors.As(err, &pe) {
			log.Errorf("binary %s unreadable; check AV quarantine and disk health", pe.Path)
		}
	}
	return err
}

Prevention

When it happens

Trigger: sha256File(binaryPath) fails: the extracted binary file does not exist, was deleted between steps, or cannot be read due to permissions; also on any underlying I/O error.

Common situations: Antivirus/EDR quarantining the freshly extracted native binary so the hash step finds it gone, a disk-full or I/O error while reading a large binary, or a temp directory cleaner removing files mid-build.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/cc17976f42c422e0. Report an issue: GitHub.

Appendix: source

Thrown at go/cmd/bundler/main.go:458

	binaryPath, tarballPath, err := downloadCLIBinary(info.runtimePlatform, info.binaryName, cliVersion, tempDir)
	if err != nil {
		return bundleArtifacts{}, fmt.Errorf("failed to download CLI binary: %w", err)
	}

	if outputDir != "." {
		if err := os.MkdirAll(outputDir, 0755); err != nil {
			return bundleArtifacts{}, fmt.Errorf("failed to create output directory: %w", err)
		}
	}
	if includeLicense {
		if err := extractCLILicense(tarballPath, outputPath); err != nil {
			return bundleArtifacts{}, fmt.Errorf("failed to extract CLI license: %w", err)
		}
	}

	binaryHash, err := sha256File(binaryPath)
	if err != nil {
		return bundleArtifacts{}, fmt.Errorf("failed to hash output binary: %w", err)
	}
	if err := compressZstdFile(binaryPath, outputPath); err != nil {
		return bundleArtifacts{}, fmt.Errorf("failed to write output binary: %w", err)
	}

	rawLibPath := filepath.Join(tempDir, "runtime.node")
	if err := extractFileFromTarball(
		tarballPath,
		tempDir,
		"package/prebuilds/"+info.runtimePlatform+"/runtime.node",
		"runtime.node",
	); err != nil {
		return bundleArtifacts{}, fmt.Errorf("runtime package is missing prebuilds/%s/runtime.node: %w", info.runtimePlatform, err)
	}
	runtimeHash, err := sha256File(rawLibPath)
	if err != nil {
		return bundleArtifacts{}, fmt.Errorf("failed to hash runtime.node: %w", err)
	}

View on GitHub (pinned to cd8cf15dc3)