{"record":{"id":"74d3a882244eb342","repo":"JuliusBrussee/caveman","slug":"cannot-remember-empty-text","errorCode":null,"errorMessage":"cannot remember empty text","messagePattern":"cannot remember empty text","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"mem/store.go","lineNumber":168,"sourceCode":"// Memory is one stored memory.\ntype Memory struct {\n\tID           string  `json:\"id\"`\n\tText         string  `json:\"text\"`\n\tCreatedAt    string  `json:\"created_at\"`\n\tValidFrom    string  `json:\"valid_from\"`\n\tValidUntil   *string `json:\"valid_until,omitempty\"`\n\tSupersedes   string  `json:\"supersedes,omitempty\"`\n\tSupersededBy string  `json:\"superseded_by,omitempty\"`\n}\n\n// Remember stores text durably and returns it with a content-addressed id.\n// Remembering identical current text twice is idempotent (same id, stored once).\n// Text that exists only as an expired historical version is rejected: returning\n// that row as success would claim it was remembered while Recall still hides it.\n// The raw text is written before any other work, so a memory is never lost.\nfunc (s *Store) Remember(text string) (Memory, error) {\n\tif strings.TrimSpace(text) == \"\" {\n\t\treturn Memory{}, fmt.Errorf(\"cannot remember empty text\")\n\t}\n\tif err := validateMemorySize(text); err != nil {\n\t\treturn Memory{}, err\n\t}\n\tid := memID(text)\n\tcreated := time.Now().UTC().Format(time.RFC3339Nano)\n\t// INSERT OR IGNORE keeps the original created_at on a repeat remember.\n\t// RetryOnBusy: under a fan-out of cavemem processes, a queued writer can\n\t// outlast a single busy_timeout (Windows file locking is the slowest case).\n\tif err := ccr.RetryOnBusy(func() error {\n\t\t_, e := s.db.Exec(\n\t\t\t`INSERT OR IGNORE INTO memories (id, text, created_at, valid_from) VALUES (?, ?, ?, ?)`,\n\t\t\tid, text, created, created,\n\t\t)\n\t\treturn e\n\t}); err != nil {\n\t\treturn Memory{}, fmt.Errorf(\"store memory: %w\", err)\n\t}","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/mem/store.go#L150-L186","documentation":"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.","triggerScenarios":"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).","commonSituations":"CLI invocation like `mem remember \"\"`, shell variable expansion where $MEMORY is unset, or upstream pipelines that strip text before calling Remember.","solutions":["Trim and check the text before calling Remember; skip the call entirely for blank input.","Fix the upstream source so the intended text is actually passed (unset variable, wrong flag).","For CLI use, pass the memory text as a quoted argument.","If blank input is legitimate in your flow, treat the error as a no-op rather than a failure."],"exampleFix":"// before\ntext := os.Getenv(\"MEMORY\")\nmem, err := store.Remember(text)\n// after\ntext := strings.TrimSpace(os.Getenv(\"MEMORY\"))\nif text == \"\" {\n    return nil // nothing to remember\n}\nmem, err := store.Remember(text)","handlingStrategy":"validation","validationCode":"// Go\nfunc canRemember(text string) bool { return strings.TrimSpace(text) != \"\" }","typeGuard":null,"tryCatchPattern":"if strings.TrimSpace(text) == \"\" { return nil }\nm, err := store.Remember(text)\nif err != nil { return fmt.Errorf(\"remember: %w\", err) }","preventionTips":["Trim and non-empty-check all text before Remember","Validate CLI/env inputs before they reach the store","Treat blank input as a no-op in pipelines","Quote shell arguments so empty expansions are caught early"],"tags":["validation","input","empty-value"],"backgroundTag":"empty-required-field","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}