charmbracelet/crush · error
failed to create .gitignore file: %q %w
Error message
failed to create .gitignore file: %q %w
What it means
setupLocalWorkspace in internal/cmd/root.go writes a `.gitignore` containing `*\n` into the data directory so crush's state is never committed. If os.WriteFile fails (permissions, read-only fs, path is a directory), it returns 'failed to create .gitignore file: %q %w'. The data dir already existed or was created, so this is a secondary but blocking failure.
Source
Thrown at internal/cmd/root.go:298
}
store, err := config.Init(cwd, dataDir, debug)
if err != nil {
return nil, nil, err
}
cfg := store.Config()
store.Overrides().SkipPermissionRequests = yolo
store.Overrides().EnabledChannels = channels
if err := os.MkdirAll(cfg.Options.DataDirectory, 0o700); err != nil {
return nil, nil, fmt.Errorf("failed to create data directory: %q %w", cfg.Options.DataDirectory, err)
}
gitIgnorePath := filepath.Join(cfg.Options.DataDirectory, ".gitignore")
if _, err := os.Stat(gitIgnorePath); os.IsNotExist(err) {
if err := os.WriteFile(gitIgnorePath, []byte("*\n"), 0o644); err != nil {
return nil, nil, fmt.Errorf("failed to create .gitignore file: %q %w", gitIgnorePath, err)
}
}
if err := projects.Register(cwd, cfg.Options.DataDirectory); err != nil {
slog.Warn("Failed to register project", "error", err)
}
conn, err := db.Connect(ctx, cfg.Options.DataDirectory)
if err != nil {
return nil, nil, err
}
logFile := filepath.Join(cfg.Options.DataDirectory, "logs", "crush.log")
crushlog.Setup(logFile, debug)
// Discover skills once before app.New. Local mode hosts a single
// workspace per process, so WithGlobalMirror keeps the package
// globals (which the TUI reads via skills.GetLatestStates) in syncView on GitHub (pinned to 7944b8e522)
Solutions
- Fix ownership/permissions of the data directory: chown -R $(whoami) <dir> && chmod u+w <dir>
- If <dir>/.gitignore is a directory, remove it (rm -rf) and retry
- Manually create the file: echo '*' > <datadir>/.gitignore, then rerun
- Mount the data directory writable if in a container
Example fix
// shell, before sudo crush run # data dir now root-owned // after sudo chown -R $(whoami) ~/.local/share/crush crush run
Defensive patterns
Strategy: validation
Validate before calling
if err := os.Chmod(dataDir, 0o700); err != nil {
return fmt.Errorf("data dir %s not writable: %w", dataDir, err)
}
os.WriteFile(filepath.Join(dataDir, ".gitignore"), []byte("*\n"), 0o644) Try / catch
if err := os.WriteFile(gitIgnorePath, []byte("*\n"), 0o644); err != nil {
if errors.Is(err, fs.ErrPermission) {
// chown/chmod the data dir or recreate it as the current user
}
return err
} Prevention
- Always run crush as the same user that owns the data directory
- Never run the CLI under sudo for normal use
- Check that .gitignore inside the data dir is not a directory
When it happens
Trigger: The data directory exists but is not writable by the current user; `.gitignore` path is actually a directory; filesystem is read-only or full; restrictive umask/ACLs.
Common situations: Data directory created previously by another user (e.g. via sudo); syncing tools (Dropbox) locking files; container volumes mounted read-only after first run; SELinux/AppArmor denials.
Related errors
- failed to create .gitignore file: %q %w
- failed to create data directory: %q %w
- failed to create parent directories: %w
- failed to create output file: %w
- failed to access file: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/10e019f3760be7d6.
Report an issue: GitHub.