github/copilot-sdk · error

existing binary hash mismatch

Error message

existing binary hash mismatch

What it means

installAt in go/internal/embeddedcli/embeddedcli.go hashes the CLI binary already present at the target path and compares it to config.CliHash. If they differ, it refuses to overwrite the binary and returns this error. The library treats a foreign or different-version binary at the destination as something it must not clobber.

Solutions

  1. Delete or rename the existing binary at finalPath and re-run install
  2. Verify the file was not corrupted or replaced (re-hash it and compare against config.CliHash)
  3. Rebuild/embed the matching CLI so config.CliHash matches the on-disk binary
  4. If overwrite is intended, add logic to remove the stale binary before calling install

Example fix

// before
path, err := embeddedcli.Install(ctx, cfg) // fails: existing binary hash mismatch
// after
if _, err := os.Stat(targetPath); err == nil {
    os.Remove(targetPath) // remove stale/mismatched binary
}
path, err := embeddedcli.Install(ctx, cfg)
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Stat(targetPath); err == nil {
    sum, _ := hashFile(targetPath)
    if !bytes.Equal(sum, cfg.CliHash) {
        os.Remove(targetPath) // or surface a friendly message
    }
}

Type guard

func binaryMatches(path string, want []byte) bool {
    got, err := hashFile(path)
    return err == nil && bytes.Equal(got, want)
}

Try / catch

path, err := embeddedcli.Install(ctx, cfg)
if err != nil {
    if strings.Contains(err.Error(), "existing binary hash mismatch") {
        os.Remove(targetPath)
        path, err = embeddedcli.Install(ctx, cfg)
    }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: Calling install (or installAt) when finalPath already exists and its SHA-256 hash does not equal config.CliHash — e.g. a stale build, a hand-placed binary, or an embedded config whose CliHash was regenerated after the on-disk binary was written.

Common situations: Upgrading the embedded CLI version without removing an older installed copy; another tool or user replaced the binary; a partially-patched binary; re-running install after modifying the embedded CLI bytes.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at go/internal/embeddedcli/embeddedcli.go:265

	// Best effort to prevent concurrent installs.
	if release, _ := flock.Acquire(filepath.Join(installDir, ".copilot-cli.lock")); release != nil {
		defer release()
	}

	binaryName := "copilot"
	if runtime.GOOS == "windows" {
		binaryName += ".exe"
	}
	finalPath := filepath.Join(installDir, binaryName)

	if _, err := os.Stat(finalPath); err == nil {
		existingHash, err := hashFile(finalPath)
		if err != nil {
			return "", fmt.Errorf("hashing existing binary: %w", err)
		}
		if !bytes.Equal(existingHash, config.CliHash) {
			return "", fmt.Errorf("existing binary hash mismatch")
		}
		if config.RuntimeExecutable != nil {
			path, err := installRuntimePair(installDir)
			if err != nil {
				return "", err
			}
			runtimePath = path
		}
		if config.RuntimeLib != nil {
			libPath, err := installRuntimeLib(installDir)
			if err != nil {
				return "", err
			}
			runtimeLibPath = libPath
		}
		if err := installRuntimeAssets(installDir); err != nil {
			return "", err
		}

View on GitHub (pinned to cd8cf15dc3)