gastownhall/beads · error
failed to remove %s: %w
Error message
failed to remove %s: %w
What it means
During uninstall, if the hook file contains a bd section whose removal leaves only a shebang (or nothing), bd deletes the whole hook file. This error wraps os.Remove failing — typically a permission problem on the file or its directory.
Source
Thrown at cmd/bd/hooks.go:1348
hookPath := filepath.Join(hooksDir, hookName)
// #nosec G304 -- hook path constrained to .git/hooks directory
content, err := os.ReadFile(hookPath)
if err != nil {
if os.IsNotExist(err) {
continue
}
return fmt.Errorf("failed to read %s: %w", hookName, err)
}
// Try to remove only the beads section (GH#1380)
newContent, found := removeHookSection(string(content))
if found {
remaining := strings.TrimSpace(newContent)
if remaining == "" || remaining == "#!/usr/bin/env sh" || remaining == "#!/bin/sh" {
// Only shebang left — remove the file entirely
if err := os.Remove(hookPath); err != nil {
return fmt.Errorf("failed to remove %s: %w", hookName, err)
}
} else {
// #nosec G306 -- git hooks must be executable
if err := os.WriteFile(hookPath, []byte(newContent), 0755); err != nil {
return fmt.Errorf("failed to write %s: %w", hookName, err)
}
}
continue
}
// No section markers — check if it's a legacy bd hook (remove entire file)
versionInfo, verr := getHookVersion(hookPath)
if verr == nil && versionInfo.IsBdHook {
if err := os.Remove(hookPath); err != nil {
return fmt.Errorf("failed to remove %s: %w", hookName, err)
}
// Restore backup if exists
backupPath := hookPath + ".backup"View on GitHub (pinned to 71377f2769)
Solutions
- Delete the hook manually: `rm -f .git/hooks/<hookName>` (with sudo if owned by root).
- Check for the immutable flag: `lsattr <hookfile>` and `chattr -i` if set.
- Ensure the .git/hooks directory is writable.
- Retry `bd hooks uninstall`.
Example fix
// before $ bd hooks uninstall // error: failed to remove pre-commit: remove .../pre-commit: permission denied // after $ sudo rm -f .git/hooks/pre-commit $ bd hooks uninstall
Defensive patterns
Strategy: validation
Validate before calling
hooksDir, _ := git.GetGitHooksDir()
if !isDirWritable(hooksDir) {
return errors.New(".git/hooks directory is not writable; fix permissions before uninstall")
} Try / catch
if err := uninstallHooks(); err != nil {
if strings.Contains(err.Error(), "failed to remove") {
log.Printf("remove the hook manually and/or restore its .backup, then retry: %v", err)
}
return err
} Prevention
- Ensure the .git/hooks directory is writable by the uninstalling user
- Do not set immutable flags (chattr +i) on hook files
- On Windows, close editors/AV holding hook files open
When it happens
Trigger: `bd hooks uninstall` -> uninstallHooks, removeHookSection found a bd section, remaining content is empty or only a shebang, and os.Remove(hookPath) fails (read-only hooks dir, file owned by another user, immutable flag, filesystem error).
Common situations: Hooks installed as root while uninstall runs as a normal user; .git/hooks on a read-only mount; chattr +i set on hook files; Windows file locks from another process.
Related errors
- resolve path: %w
- failed to stat %s: %w
- refusing to write migrated hook %s: %w
- writing migrated hook %s: %w
- reading source content for %s from %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/34b0d1376dbd5a12.
Report an issue: GitHub.