gastownhall/beads · error
beadsDir must not be empty
Error message
beadsDir must not be empty
What it means
WriteLastPullTimestamp records the current UTC time (ISO 8601) into <beadsDir>/.beads/last_pull to support pull staleness checks. It validates its input first: if beadsDir is an empty string it returns this sentinel error instead of attempting to write a file at a meaningless path. This is a programmer-error guard, not a runtime condition.
Source
Thrown at internal/linear/staleness.go:20
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
)
const (
lastPullFileName = "last_pull"
DefaultStaleThreshold = 20 * time.Minute
debounceThreshold = 5 * time.Minute
)
// WriteLastPullTimestamp writes the current time as ISO 8601 to .beads/last_pull.
func WriteLastPullTimestamp(beadsDir string) error {
if beadsDir == "" {
return fmt.Errorf("beadsDir must not be empty")
}
path := filepath.Join(beadsDir, lastPullFileName)
ts := time.Now().UTC().Format(time.RFC3339)
return os.WriteFile(path, []byte(ts+"\n"), 0600)
}
// ReadLastPullTimestamp reads the last pull timestamp from .beads/last_pull.
// Returns the zero time if the file doesn't exist or is unreadable.
func ReadLastPullTimestamp(beadsDir string) (time.Time, error) {
if beadsDir == "" {
return time.Time{}, fmt.Errorf("beadsDir must not be empty")
}
path := filepath.Join(beadsDir, lastPullFileName)
data, err := os.ReadFile(path) // #nosec G304 -- path is constrained to the beads directory.
if err != nil {
if os.IsNotExist(err) {
return time.Time{}, nil
}View on GitHub (pinned to 71377f2769)
Solutions
- Ensure the beads directory is resolved before calling (default to ./.beads or the project root's .beads)
- Check the flag/env/config value feeding beadsDir for emptiness at startup
- Return or surface the configuration error earlier instead of passing an empty string down
- In tests, pass t.TempDir() rather than ""
Example fix
// before
WriteLastPullTimestamp(cfg.BeadsDir) // cfg.BeadsDir may be ""
// after
if cfg.BeadsDir == "" {
return fmt.Errorf("beads dir not configured")
}
WriteLastPullTimestamp(cfg.BeadsDir) Defensive patterns
Strategy: validation
Validate before calling
if beadsDir == "" {
return fmt.Errorf("beads dir is not configured")
}
// safe to call
err := WriteLastPullTimestamp(beadsDir) Type guard
null
Try / catch
null
Prevention
- Default the beads directory at config load time (e.g. ./.beads) instead of allowing empty
- Validate configuration once at startup, not at each call site
- Use t.TempDir() in tests instead of empty strings
When it happens
Trigger: Calling WriteLastPullTimestamp("") — typically because the caller derived the beads directory from an unset config value, empty flag, or failed path resolution before writing the timestamp after a pull.
Common situations: A --beads-dir flag left empty and not defaulted; an environment variable (e.g. BEADS_DIR) unset; a config struct field not populated because initialization was skipped in tests or a new code path.
Related errors
- directory path is empty
- multiple .doltcfg directories detected
- identity: invalid proxy secret
- backend must be set
- remote target %s is non-empty but is neither a bare git repo
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/6fa187114fde7d4f.
Report an issue: GitHub.