JuliusBrussee/caveman · warning

cannot remember empty text

Error message

cannot remember empty text

What it means

Remember() rejects text that is empty or consists only of whitespace, because storing a blank memory would pollute the store and be unusable in recall. The check happens first, before any id computation or database write.

Solutions

  1. Trim and check the text before calling Remember; skip the call entirely for blank input.
  2. Fix the upstream source so the intended text is actually passed (unset variable, wrong flag).
  3. For CLI use, pass the memory text as a quoted argument.
  4. If blank input is legitimate in your flow, treat the error as a no-op rather than a failure.

Example fix

// before
text := os.Getenv("MEMORY")
mem, err := store.Remember(text)
// after
text := strings.TrimSpace(os.Getenv("MEMORY"))
if text == "" {
    return nil // nothing to remember
}
mem, err := store.Remember(text)
Defensive patterns

Strategy: validation

Validate before calling

// Go
func canRemember(text string) bool { return strings.TrimSpace(text) != "" }

Try / catch

if strings.TrimSpace(text) == "" { return nil }
m, err := store.Remember(text)
if err != nil { return fmt.Errorf("remember: %w", err) }

Prevention

When it happens

Trigger: Calling Store.Remember(""), Remember(" "), Remember("\n\t"), or passing unvalidated user/CLI input whose text field ended up blank (e.g. cmdRemember with an empty argument or a dropped flag value).

Common situations: CLI invocation like `mem remember ""`, shell variable expansion where $MEMORY is unset, or upstream pipelines that strip text before calling Remember.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/74d3a882244eb342. Report an issue: GitHub.

Appendix: source

Thrown at mem/store.go:168

// Memory is one stored memory.
type Memory struct {
	ID           string  `json:"id"`
	Text         string  `json:"text"`
	CreatedAt    string  `json:"created_at"`
	ValidFrom    string  `json:"valid_from"`
	ValidUntil   *string `json:"valid_until,omitempty"`
	Supersedes   string  `json:"supersedes,omitempty"`
	SupersededBy string  `json:"superseded_by,omitempty"`
}

// Remember stores text durably and returns it with a content-addressed id.
// Remembering identical current text twice is idempotent (same id, stored once).
// Text that exists only as an expired historical version is rejected: returning
// that row as success would claim it was remembered while Recall still hides it.
// The raw text is written before any other work, so a memory is never lost.
func (s *Store) Remember(text string) (Memory, error) {
	if strings.TrimSpace(text) == "" {
		return Memory{}, fmt.Errorf("cannot remember empty text")
	}
	if err := validateMemorySize(text); err != nil {
		return Memory{}, err
	}
	id := memID(text)
	created := time.Now().UTC().Format(time.RFC3339Nano)
	// INSERT OR IGNORE keeps the original created_at on a repeat remember.
	// RetryOnBusy: under a fan-out of cavemem processes, a queued writer can
	// outlast a single busy_timeout (Windows file locking is the slowest case).
	if err := ccr.RetryOnBusy(func() error {
		_, e := s.db.Exec(
			`INSERT OR IGNORE INTO memories (id, text, created_at, valid_from) VALUES (?, ?, ?, ?)`,
			id, text, created, created,
		)
		return e
	}); err != nil {
		return Memory{}, fmt.Errorf("store memory: %w", err)
	}

View on GitHub (pinned to 3ee70a1026)