gastownhall/beads · error
writing migrated hook %s: %w
Error message
writing migrated hook %s: %w
What it means
After the safety guard passes, bd writes the migrated hook with os.WriteFile (mode 0755, since git hooks must be executable). This error wraps any OS-level write failure — permissions, missing directory, disk full, immutable file — with the hook's path for context.
Source
Thrown at cmd/bd/migrate_hooks_apply.go:265
}
if err := validateRetireCollisionPolicy(execPlan.RetireOps); err != nil {
return hookMigrationApplySummary{}, err
}
summary := hookMigrationApplySummary{
WrittenHooks: make([]string, 0, len(preparedWrites)),
RetiredArtifacts: make([]string, 0, len(execPlan.RetireOps)),
SkippedArtifacts: make([]string, 0),
}
for _, write := range preparedWrites {
if err := guardHookWritePath(write.Path, false); err != nil {
return summary, fmt.Errorf("refusing to write migrated hook %s: %w", write.HookName, err)
}
// #nosec G306 -- git hooks must be executable for Git to run them
if err := os.WriteFile(write.Path, write.Content, 0755); err != nil {
return summary, fmt.Errorf("writing migrated hook %s: %w", write.Path, err)
}
summary.WrittenHooks = append(summary.WrittenHooks, write.HookName)
}
for _, retire := range execPlan.RetireOps {
retired, retiredErr := retireHookSidecar(retire)
if retiredErr != nil {
return summary, retiredErr
}
if retired == "" {
summary.SkippedArtifacts = append(summary.SkippedArtifacts, retire.SourcePath)
continue
}
summary.RetiredArtifacts = append(summary.RetiredArtifacts, retired)
}
summary.WrittenHookCount = len(summary.WrittenHooks)
summary.RetiredCount = len(summary.RetiredArtifacts)View on GitHub (pinned to 71377f2769)
Solutions
- Fix permissions: `chown` the hooks directory to the current user and ensure it's writable
- Check the mount is not read-only (`mount | grep <path>`)
- Free disk space if the filesystem is full
- Retry `bd migrate hooks apply` once the filesystem condition is fixed
Defensive patterns
Strategy: try-catch
Validate before calling
// verify writability before applying fs.accessSync(hooksDir, fs.constants.W_OK);
Try / catch
if err := apply(...); err != nil && strings.Contains(err.Error(), "writing migrated hook") {
// inspect wrapped OS error: check permissions, disk space, read-only mount, then retry
} Prevention
- Ensure the repo owner runs the migration (not root/sudo)
- Check disk space on read-heavy CI runners
- Avoid running migration on read-only mounts
When it happens
Trigger: os.WriteFile(write.Path, write.Content, 0755) returned an error during applyHookMigrationExecution, after guardHookWritePath succeeded.
Common situations: Read-only checkout or hooks directory owned by root/another user; worktree on a read-only mount; disk full; path disappeared between guard and write.
Related errors
- failed to stat %s: %w
- checking source sidecar %s: %w
- dolt path is not executable
- failed to create backup directory: %w
- failed to create temp file: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/aa2d7d5002baa17f.
Report an issue: GitHub.