{"record":{"id":"819162b8edf07ed9","repo":"gastownhall/beads","slug":"memory-key-must-not-be-empty","errorCode":null,"errorMessage":"memory key must not be empty","messagePattern":"memory key must not be empty","errorType":"validation","errorClass":"memoryops.ErrValidation","httpStatus":null,"severity":"warning","filePath":"internal/memoryapi/memoryapi.go","lineNumber":96,"sourceCode":"// reading since the command shipped, and the sentinel is what code classifies\n// on.\nfunc ValidateContent(content string) error {\n\tif strings.TrimSpace(content) == \"\" {\n\t\treturn fmt.Errorf(\"%w: memory content cannot be empty\", memoryops.ErrValidation)\n\t}\n\treturn nil\n}\n\n// ValidateKey checks a key a caller wants to read or remove, and returns it\n// UNCHANGED.\n//\n// Unchanged is the whole point: `bd remember --key` accepts any string, so a\n// key differing from another only by surrounding space is a key someone may\n// genuinely hold, and trimming it here would answer a different question from\n// the one asked. The only rule is that a key has to name something.\nfunc ValidateKey(key string) (string, error) {\n\tif strings.TrimSpace(key) == \"\" {\n\t\treturn \"\", fmt.Errorf(\"%w: memory key must not be empty\", memoryops.ErrValidation)\n\t}\n\treturn key, nil\n}\n\n// ResolveKey answers which key a Remember lands under: the caller's if it gave\n// one, otherwise the derivation of the content.\n//\n// It is one function rather than a derivation at each implementation because\n// the ORDER matters and is invisible once it is spelled twice: an explicit key\n// is used verbatim even when it is content-shaped, and content is only ever\n// derived from when no key was given. The refusal for content that derives to\n// nothing lives here too, so a caller cannot get a row under the empty key by\n// reaching the write through a body that forgot to check.\nfunc ResolveKey(key, content string) (string, error) {\n\tif err := ValidateContent(content); err != nil {\n\t\treturn \"\", err\n\t}\n\tif key != \"\" {","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/memoryapi/memoryapi.go#L78-L114","documentation":"ValidateKey requires that an explicitly supplied memory key names something: empty or whitespace-only keys are rejected with memoryops.ErrValidation. Keys that pass are returned UNCHANGED — surrounding space is deliberately preserved because a user may genuinely hold such a key via bd remember --key.","triggerScenarios":"Calling ValidateKey(\"\") or a whitespace-only string; bd remember --key \"   \"; ResolveKey delegating to ValidateKey with a blank explicit key.","commonSituations":"--key flag fed from an unset shell variable; script passing an empty placeholder key; copy-pasted key that lost its content in transit.","solutions":["Supply a non-empty key via --key or the key argument.","Check the variable feeding --key is set and non-blank.","If unsure of a key, omit --key and let bd derive one from the content."],"exampleFix":"// before\nkey, err := memoryapi.ValidateKey(os.Args[2]) // may be \"\"\n// after\nif strings.TrimSpace(os.Args[2]) == \"\" {\n    return fmt.Errorf(\"--key requires a value\")\n}\nkey, err := memoryapi.ValidateKey(os.Args[2])","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(key) == \"\" {\n    return fmt.Errorf(\"--key requires a non-empty value\")\n}","typeGuard":"func hasKey(s string) bool { return strings.TrimSpace(s) != \"\" }","tryCatchPattern":"key, err := memoryapi.ValidateKey(providedKey)\nif err != nil {\n    if errors.Is(err, memoryops.ErrValidation) {\n        return fmt.Errorf(\"provide --key or omit it to derive from content\")\n    }\n    return err\n}","preventionTips":["Never feed unset variables into --key without checking.","Prefer letting bd derive the key when unsure.","Keep key arguments quoted in shell scripts."],"tags":["validation","memory","empty-input"],"backgroundTag":"empty-input-validation","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}