gastownhall/beads · error

building hook migration plan: %w

Error message

building hook migration plan: %w

What it means

fixPendingMigrations wraps failures from doctor.PlanHookMigration when building the plan to migrate git hooks. The %w-wrapped inner error explains why planning failed (e.g. unreadable hook directory or a malformed hook marker). It surfaces during `bd doctor fix` runs.

Source

Thrown at cmd/bd/doctor_fix.go:448

	// Summary
	fmt.Printf("\nFix summary: %d fixed, %d errors\n", fixedCount, errorCount)
	if errorCount > 0 {
		fmt.Println("\nSome fixes failed. Please review the errors above and apply manual fixes as needed.")
	}
}

func fixPendingMigrations(path string) error {
	pending := doctor.DetectPendingMigrations(path)
	if len(pending) == 0 {
		return nil
	}

	for _, migration := range pending {
		switch migration.Name {
		case "hooks":
			plan, err := doctor.PlanHookMigration(path)
			if err != nil {
				return fmt.Errorf("building hook migration plan: %w", err)
			}

			execPlan := buildHookMigrationExecutionPlan(plan)
			if len(execPlan.BlockingErrors) > 0 {
				return fmt.Errorf("hook migration is blocked:\n- %s", strings.Join(execPlan.BlockingErrors, "\n- "))
			}

			summary, err := applyHookMigrationExecution(execPlan)
			if err != nil {
				return fmt.Errorf("applying hook migration: %w", err)
			}

			fmt.Printf(
				"  Hook migration applied: %d hook(s) written, %d artifact(s) retired, %d artifact(s) skipped\n",
				summary.WrittenHookCount,
				summary.RetiredCount,
				summary.SkippedCount,
			)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped cause (%w) printed below this message and address it directly
  2. Inspect .git/hooks for corrupt or partially written hook files and remove/repair them
  3. Re-run `bd doctor` to confirm the migration is still detected, then retry `bd fix`
  4. If the marker is broken, let the repair path run: re-run `bd fix` (TestFixPendingMigrations_BrokenMarkerIsRepaired covers this)
Defensive patterns

Strategy: validation

Validate before calling

if fi, err := os.Stat(filepath.Join(gitDir, "hooks")); err != nil || !fi.IsDir() {
  return fmt.Errorf("hooks dir unreadable: %w", err)
}

Try / catch

if err := fixPendingMigrations(pending, path); err != nil {
  if strings.Contains(err.Error(), "building hook migration plan") {
    // inspect the wrapped cause with errors.Unwrap / %v for the real problem
  }
  return err
}

Prevention

When it happens

Trigger: Running `bd fix` / `bd doctor --fix` while a 'hooks' migration is pending and PlanHookMigration(path) returns an error — typically unreadable .git/hooks, a corrupt or half-written hook marker file, or permission errors on the hook files.

Common situations: A previous interrupted migration left a broken marker; .git/hooks owned by another user; running bd inside a worktree or bare repo where hooks paths differ.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/efc354f04caba025. Report an issue: GitHub.