{"record":{"id":"c91f427756c01f17","repo":"gastownhall/beads","slug":"key-cannot-be-only-whitespace","errorCode":null,"errorMessage":"key cannot be only whitespace","messagePattern":"key cannot be only whitespace","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/kv.go","lineNumber":25,"sourceCode":"\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n\n\t\"github.com/steveyegge/beads/internal/metrics\"\n\t\"github.com/steveyegge/beads/internal/storage/kvkeys\"\n)\n\n// kvPrefix is prepended to all user keys to separate them from internal config\nconst kvPrefix = kvkeys.Prefix\n\n// validateKVKey checks if a key is valid for the KV store.\n// Returns an error if the key is invalid.\nfunc validateKVKey(key string) error {\n\tif key == \"\" {\n\t\treturn fmt.Errorf(\"key cannot be empty\")\n\t}\n\tif strings.TrimSpace(key) == \"\" {\n\t\treturn fmt.Errorf(\"key cannot be only whitespace\")\n\t}\n\t// Prevent keys that would create nested kv.kv.* prefixes\n\tif strings.HasPrefix(key, kvPrefix) {\n\t\treturn fmt.Errorf(\"key cannot start with 'kv.' (would create nested prefix)\")\n\t}\n\t// Reserve the persistent-memory namespace: a generic memory.* key would\n\t// store to kv.memory.*, indistinguishable from a `bd remember` memory, and\n\t// the merge resolver auto-resolves kv.memory.* conflicts with --theirs\n\t// (GH#2474). Without this guard a user's deliberate kv value could be\n\t// silently overridden by a remote on pull. Keep the namespace owned by\n\t// bd remember / bd forget.\n\tif strings.HasPrefix(key, kvkeys.MemoryPrefix) {\n\t\treturn fmt.Errorf(\"key cannot start with %q (reserved for persistent memories; use 'bd remember' / 'bd forget')\", kvkeys.MemoryPrefix)\n\t}\n\t// Prevent keys that look like internal config\n\tif strings.HasPrefix(key, \"sync.\") || strings.HasPrefix(key, \"conflict.\") ||\n\t\tstrings.HasPrefix(key, \"federation.\") || strings.HasPrefix(key, \"jira.\") ||\n\t\tstrings.HasPrefix(key, \"linear.\") || strings.HasPrefix(key, \"export.\") ||","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/kv.go#L7-L43","documentation":"validateKVKey trims the key; if only whitespace remains (spaces, tabs, newlines) the key is functionally meaningless in the store, so the CLI rejects it. This catches keys that pass a naive `key == \"\"` check but are still unusable.","triggerScenarios":"Calling `bd kv set \"   \" value` or any key consisting solely of whitespace characters through the kv set path.","commonSituations":"Copy-pasting a key with trailing spaces; shell scripts building keys from padded output of another command (`$(...)` results containing newlines).","solutions":["Trim the key before passing it: bd kv set \"$(echo \"$KEY\" | xargs)\" value or similar.","Re-run with a key containing at least one non-whitespace character.","Inspect the key with `printf '%q' \"$KEY\"` in bash to reveal hidden whitespace."],"exampleFix":"// before\nbd kv set \"  \" \"v\"   // rejected\n// after\nbd kv set \"settings.timeout\" \"30\"","handlingStrategy":"validation","validationCode":"case \"$KEY\" in *[![:space:]]*) bd kv set \"$KEY\" \"$VALUE\";; *) echo \"key must contain non-whitespace\" >&2; exit 1;; esac","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Trim keys from command substitution before use (xargs, parameter expansion).","Quote variables and inspect with printf '%q' when debugging.","Centralize key construction in one helper that strips whitespace."],"tags":["cli","validation","kv-store"],"backgroundTag":"invalid-input-key","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}