github/copilot-sdk · error

restoring existing permissions

Error message

restoring existing %s permissions: %w

What it means

If an existing, hash-verified file lacks the execute bits required by the asset mode, installVerifiedFile adds them via os.Chmod(path, existingPerm | mode&0111). This error wraps a Chmod failure — the file's permissions could not be updated to make it executable.

Solutions

  1. Run the install as the file's owner or with elevated privileges (sudo) so chmod can succeed.
  2. chown the installed file to the user running the application.
  3. Remove the file and reinstall so it is created fresh with the correct mode.

Example fix

// before
$ ls -l bin/cli-server  # owned by root, no exec bit
// after
$ sudo chown $(whoami) bin/cli-server && $APP reinstall
Defensive patterns

Strategy: try-catch

Try / catch

if err := client.InstallAt(dir); err != nil {
    var pe *fs.PathError
    if strings.Contains(err.Error(), "restoring existing") {
        // advise running as the file owner or deleting the file
        _ = pe
    }
}

Prevention

When it happens

Trigger: os.Chmod fails while restoring the executable bit on an existing hash-matching file, typically because the current user is not the file's owner and lacks permission to change its mode.

Common situations: The binary was previously installed by root (or another user) and is now being reused/verified by a non-privileged user on Linux/macOS; read-only mount points that reject chmod.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


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

Appendix: source

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

}

func installVerifiedFile(path string, reader io.Reader, expectedHash []byte, mode os.FileMode, label string) error {
	if _, err := os.Stat(path); err == nil {
		existingHash, err := hashFile(path)
		if err != nil {
			return fmt.Errorf("hashing existing %s: %w", label, err)
		}
		if !bytes.Equal(existingHash, expectedHash) {
			return fmt.Errorf("existing %s hash mismatch", label)
		}
		if runtime.GOOS != "windows" && mode.Perm()&0111 != 0 {
			info, err := os.Stat(path)
			if err != nil {
				return fmt.Errorf("checking existing %s permissions: %w", label, err)
			}
			if info.Mode().Perm()&0111 == 0 {
				if err := os.Chmod(path, info.Mode().Perm()|mode.Perm()&0111); err != nil {
					return fmt.Errorf("restoring existing %s permissions: %w", label, err)
				}
			}
		}
		return nil
	}

	tmp, err := os.CreateTemp(filepath.Dir(path), ".copilot-runtime-pair-*.tmp")
	if err != nil {
		return fmt.Errorf("creating temporary %s: %w", label, err)
	}
	tmpPath := tmp.Name()
	h := sha256.New()
	_, err = io.Copy(io.MultiWriter(tmp, h), reader)
	if err1 := tmp.Chmod(mode); err1 != nil && err == nil {
		err = err1
	}
	if err1 := tmp.Close(); err1 != nil && err == nil {
		err = err1

View on GitHub (pinned to cd8cf15dc3)