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
- Run the install as the file's owner or with elevated privileges (sudo) so chmod can succeed.
- chown the installed file to the user running the application.
- 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
- Install and run as the same OS user
- Don't install with sudo then run as a normal user
- Ensure install filesystem supports chmod (not some read-only mounts)
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
- failed to chmod binary
- Published runtime wrapper is not a non-empty executable…
- Failed to make Copilot CLI executable:
- creating install directory
- creating runtime asset directory
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 = err1View on GitHub (pinned to cd8cf15dc3)