{"record":{"id":"ae40aeaf8c313cae","repo":"gastownhall/beads","slug":"key-cannot-start-with-kv-would-create-nested-p","errorCode":null,"errorMessage":"key cannot start with 'kv.' (would create nested prefix)","messagePattern":"key cannot start with 'kv\\.' \\(would create nested prefix\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/kv.go","lineNumber":29,"sourceCode":"\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.\") ||\n\t\tstrings.HasPrefix(key, \"import.\") {\n\t\treturn fmt.Errorf(\"key cannot start with reserved prefix %q\", strings.Split(key, \".\")[0]+\".\")\n\t}\n\treturn nil","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/kv.go#L11-L47","documentation":"Keys are stored under the `kv.` prefix internally; a user key beginning with `kv.` would create a nested `kv.kv.*` prefix, corrupting the namespace layout. validateKVKey rejects such keys to keep the key space flat.","triggerScenarios":"Running `bd kv set kv.foo value` or any key with the literal `kv.` prefix.","commonSituations":"Users assuming keys must repeat the store's prefix (writing `kv.mykey` because values live in kv.* internally); migration scripts from another tool that prefixed keys with `kv.`.","solutions":["Drop the `kv.` prefix: use bd kv set foo value instead of kv.foo.","If migrating, strip the prefix programmatically before setting keys.","Read `bd kv --help` for key naming rules."],"exampleFix":"// before\nbd kv set kv.mykey \"v\"   // rejected\n// after\nbd kv set mykey \"v\"","handlingStrategy":"validation","validationCode":"case \"$KEY\" in kv.*) echo \"strip the kv. prefix\" >&2; exit 1;; esac\nbd kv set \"$KEY\" \"$VALUE\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never include the store prefix in user-supplied keys.","Document key naming conventions for team scripts.","Validate keys in a shared helper before any bd kv set call."],"tags":["cli","validation","kv-store","namespace"],"backgroundTag":"invalid-input-key","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}