gastownhall/beads · error

failed to create hooks directory: %w

Error message

failed to create hooks directory: %w

What it means

installGitHooks ensures the repository's git hooks directory exists with os.MkdirAll(hooksDir, 0750) before writing bd hooks. If the directory cannot be created, the mkdir error is wrapped with this message. `bd init` (hook installation) fails before any hook file is written.

Source

Thrown at cmd/bd/init_git_hooks.go:140

			if !hooks[i].isBdHook {
				hooks[i].isPreCommitFramework = preCommitFrameworkPattern.MatchString(hooks[i].content)
			}
		}
	}

	return hooks
}

// installGitHooks installs git hooks inline (no external dependencies)
func installGitHooks() error {
	hooksDir, err := git.GetGitHooksDir()
	if err != nil {
		return err
	}

	// Ensure hooks directory exists
	if err := os.MkdirAll(hooksDir, 0750); err != nil {
		return fmt.Errorf("failed to create hooks directory: %w", err)
	}

	// Detect existing hooks
	existingHooks := detectExistingHooks()

	// Check if any non-bd hooks exist
	hasExistingHooks := false
	for _, hook := range existingHooks {
		if hook.exists && !hook.isBdHook {
			hasExistingHooks = true
			break
		}
	}

	// Default to chaining with existing hooks (no prompting)
	chainHooks := hasExistingHooks
	if chainHooks {
		// Chain mode - rename existing hooks to .old so they can be called

View on GitHub (pinned to 71377f2769)

Solutions

  1. Confirm you are in a git repository with a .git directory; run `git rev-parse --git-dir` to verify.
  2. Check that `.git/hooks` is a directory, not a file, and remove/fix it if not.
  3. Fix permissions: ensure the .git directory is writable (chmod/chown), especially in CI or container mounts.
  4. Install hooks manually after fixing, or skip with init's no-hooks option.

Example fix

// before
$ ls .git/hooks
hooks: Not a directory
// after
$ rm -f .git/hooks && mkdir .git/hooks
$ bd init
Defensive patterns

Strategy: validation

Validate before calling

hooksDir := filepath.Join(gitDir, "hooks")
if fi, err := os.Stat(hooksDir); err == nil && !fi.IsDir() {
    return fmt.Errorf("%s exists and is not a directory", hooksDir)
}
if fi, err := os.Stat(gitDir); err == nil && fi.Mode()&0200 == 0 {
    return fmt.Errorf("%s is not writable", gitDir)
}

Try / catch

if err := installGitHooks(hooksDir); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && pe.Op == "mkdir" {
        // fix .git/hooks path/permissions, then retry
    }
    return err
}

Prevention

When it happens

Trigger: os.MkdirAll fails on the resolved hooks path — the .git directory is missing (not a git repo or bare worktree layout), the parent directory is read-only, or a non-directory file named `hooks` already exists at the target path.

Common situations: Running `bd init` outside a git repo where hooksDir can't be created, in a repo with a read-only .git directory (CI checkouts), or after someone replaced .git/hooks with a regular file.

Related errors


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