gastownhall/beads · error
failed to create interactions log: %w
Error message
failed to create interactions log: %w
What it means
EnsureFile creates .beads/interactions.jsonl and returns an error wrapped as "failed to create interactions log" when os.OpenFile with O_CREATE|O_EXCL fails with an error other than os.ErrExist. This guards the create-only race in the audit sidecar: a concurrent creator winning the O_EXCL race is treated as success, any other open failure is surfaced here. The error is always a wrapped underlying OS error.
Source
Thrown at internal/audit/audit.go:103
p, err := Path()
if err != nil {
return "", err
}
if err := os.MkdirAll(filepath.Dir(p), 0700); err != nil {
return "", fmt.Errorf("failed to create .beads directory: %w", err)
}
if ensureFileBeforeCreateHook != nil {
ensureFileBeforeCreateHook(p)
}
f, err := os.OpenFile(p, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644) // nolint:gosec // JSONL is intended to be shared via git across clones/tools.
if err == nil {
if closeErr := f.Close(); closeErr != nil {
return "", fmt.Errorf("failed to close interactions log: %w", closeErr)
}
return p, nil
}
if !errors.Is(err, os.ErrExist) {
return "", fmt.Errorf("failed to create interactions log: %w", err)
}
return p, nil
}
// Append appends an event to .beads/interactions.jsonl as a single JSON line.
// This is intentionally append-only: callers must not mutate existing lines.
func Append(e *Entry) (string, error) {
if e == nil {
return "", fmt.Errorf("nil entry")
}
if e.Kind == "" {
return "", fmt.Errorf("kind is required")
}
p, err := EnsureFile()
if err != nil {
return "", err
}View on GitHub (pinned to 71377f2769)
Solutions
- Fix filesystem permissions on the .beads directory so the current user can create files (chmod/chown).
- Check that the target path is on a writable filesystem, not a read-only mount or read-only container layer.
- Verify BEADS_DIR points to an existing writable directory.
- Inspect the wrapped %w cause with errors.Is/errors.As to identify the exact OS error.
- If you need audit logging, run bd from a checkout that has (or can create) a .beads directory.
Example fix
// before
p, err := audit.AppendIfEnabled(entry) // fails: permission denied in shared clone
// after
if err := os.Chmod(".beads", 0o700); err != nil { log.Fatal(err) } // or chown the checkout
p, err := audit.AppendIfEnabled(entry) Defensive patterns
Strategy: try-catch
Validate before calling
if _, statErr := os.Stat(".beads"); statErr != nil && os.IsPermission(statErr) {
return fmt.Errorf("cannot write .beads: %w", statErr)
} Try / catch
if _, err := audit.AppendIfEnabled(entry); err != nil {
if errors.Is(err, fs.ErrPermission) || errors.Is(err, syscall.EROFS) {
log.Printf("audit log not writable: %v", err)
return nil // degrade gracefully
}
return err
} Prevention
- Run bd from a checkout you own and can write to.
- Keep .beads/ on a writable filesystem, not a read-only mount.
- Check BEADS_DIR before running in shared environments.
- Unwrap errors with errors.Is to distinguish permission vs existence problems.
When it happens
Trigger: Calling Append or AppendIfEnabled (which call EnsureFile) when Path() fails, os.MkdirAll of .beads fails (wrapped differently), or OpenFile(O_EXCL) fails with permission denied, a read-only filesystem, or a non-ErrExist error like EACCES/ENOTDIR on the interactions.jsonl path.
Common situations: Running bd in a repo checkout where .beads/ or the file is owned by another user; CI containers with read-only workspaces; BEADS_DIR pointing into a directory the current user cannot write; antivirus or filesystem restrictions blocking creation.
Related errors
- dolt path is not executable
- failed to create backup directory: %w
- failed to create temp file: %w
- failed to create backup file: %w
- %d artifact(s) could not be removed
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/efb063b8649a6986.
Report an issue: GitHub.