gastownhall/beads · error

nil entry

Error message

nil entry

What it means

Append validates its *Entry argument before touching the audit log and returns this plain error when the caller passes a nil pointer. It is a programmer-error guard, not an environmental failure — the library never constructs nil entries itself. The error message is the literal string "nil entry" with no wrapping.

Source

Thrown at internal/audit/audit.go:112

	}
	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
	}

	if e.ID == "" {
		e.ID, err = newID()
		if err != nil {
			return "", err
		}
	}
	if e.CreatedAt.IsZero() {
		e.CreatedAt = time.Now().UTC()

View on GitHub (pinned to 71377f2769)

Solutions

  1. Pass a non-nil *audit.Entry with at least Kind set.
  2. Check the pointer for nil before calling Append.
  3. If the entry comes from another function, check that function's error before using its result.
  4. Set BD_AUDIT_ENABLED/audit.enabled and retry only after fixing the caller; this error is not environment-related.

Example fix

// before
audit.Append(entry) // panics-free but returns "nil entry" because entry == nil
// after
if entry == nil {
    return fmt.Errorf("no audit entry to record")
}
if _, err := audit.Append(entry); err != nil {
    return fmt.Errorf("audit: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

if entry == nil {
    return fmt.Errorf("refusing to append: audit entry is nil")
}

Type guard

func validEntry(e *audit.Entry) bool { return e != nil }

Try / catch

if err != nil && err.Error() == "nil entry" {
    return fmt.Errorf("caller bug: constructed nil audit entry")
}

Prevention

When it happens

Trigger: Calling audit.Append(nil) directly, or AppendIfEnabled(nil), or a variable holding *audit.Entry that was never initialized (e.g. a function returning (nil, err) whose err was ignored before appending).

Common situations: Constructing entries conditionally and forgetting a branch; passing the result of another constructor that returned nil on failure; refactors changing signatures from value to pointer types.

Related errors


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