{"record":{"id":"c57f6e61e2738189","repo":"gastownhall/beads","slug":"invalid-key-q-expected-storage-class-issue-type","errorCode":null,"errorMessage":"invalid key %q: expected storage-class.<issue-type> (e.g. storage-class.event)","messagePattern":"invalid key %q: expected storage-class\\.<issue-type> \\(e\\.g\\. storage-class\\.event\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/bd/config.go","lineNumber":986,"sourceCode":"// they are derived from the tracker registry at runtime via\n// allRecognizedConfigPrefixes, so the recognizer cannot drift out of sync when\n// a new tracker is added (GH#4427).\nvar recognizedConfigPrefixes = []string{\n\t\"export.\", \"import.\", \"dolt.\", \"custom.\",\n\t\"status.\", \"types.\", \"doctor.suppress.\", \"routing.\", \"sync.\", \"git.\",\n\t\"directory.\", \"repos.\", \"external_projects.\", \"validation.\",\n\t\"lint.\", \"hierarchy.\", \"ai.\", \"backup.\", \"federation.\", \"metrics.\",\n\t\"agent.\", \"claim.\", \"storage-class.\",\n}\n\n// validateStorageClassConfig validates a storage-class.<type> per-type\n// default at config-set time (Protocol v0.1 C-OQ1: values are validated when\n// set, not discovered broken at create time). The key suffix must name an\n// issue type and the value must be a storage class.\nfunc validateStorageClassConfig(key, value string) error {\n\tsuffix := strings.TrimPrefix(key, \"storage-class.\")\n\tif suffix == \"\" || strings.Contains(suffix, \".\") {\n\t\treturn fmt.Errorf(\"invalid key %q: expected storage-class.<issue-type> (e.g. storage-class.event)\", key)\n\t}\n\t// The key suffix must be a canonical, known issue type: create-time lookup\n\t// keys on the Normalize()d type (resolveStorageClass), so an alias like\n\t// storage-class.feat or a typo like storage-class.taks would pass set-time\n\t// validation and then silently never match — the C-OQ1 failure mode this\n\t// validator exists to prevent.\n\tissueType := types.IssueType(suffix)\n\tif canonical := issueType.Normalize(); canonical != issueType {\n\t\treturn fmt.Errorf(\"invalid key %q: %q is an alias of %q, and create-time lookup uses the canonical type; set storage-class.%s instead\", key, suffix, canonical, canonical)\n\t}\n\tif !issueType.IsValidWithCustom(loadEmbeddedCustomTypes()) {\n\t\treturn fmt.Errorf(\"invalid key %q: unknown issue type %q (use a built-in type, or add it to types.custom first)\", key, suffix)\n\t}\n\tif _, err := types.ParseStorageClass(value); err != nil {\n\t\treturn err\n\t}\n\treturn nil\n}","sourceCodeStart":968,"sourceCodeEnd":1004,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/cmd/bd/config.go#L968-L1004","documentation":"Set-time validation for storage-class config keys: the key must be `storage-class.<issue-type>` with exactly one dot and a non-empty suffix naming a canonical issue type. Anything else (empty suffix, extra dots like `storage-class.a.b`) is rejected when the config value is being set, per Protocol v0.1 C-OQ1.","triggerScenarios":"Running `bd config set storage-class.<something> <value>` where the suffix is empty (`storage-class.`) or contains another dot — e.g. `storage-class.bug.extra` or a bare `storage-class.` key.","commonSituations":"Typo with a trailing dot, nesting keys by habit (`storage-class.chore.subtype`), or scripting config sets with a malformed key template.","solutions":["Use the form storage-class.<issue-type>, e.g. `bd config set storage-class.event ephemeral`","Remove any extra dot-separated segments from the key","Confirm the issue-type suffix is canonical (not an alias like 'feat') — a later check also rejects aliases/typos","Run `bd config list` to see existing valid keys as examples"],"exampleFix":"// before\nbd config set storage-class.bug.extra ephemeral\n// after\nbd config set storage-class.bug ephemeral","handlingStrategy":"validation","validationCode":"# validate key shape before set\ncase \"$KEY\" in\n  storage-class.[a-z]*) : ;;\n  *) echo \"invalid: use storage-class.<issue-type>\"; exit 1 ;;\nesac","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use canonical issue-type names (bug, feature, task, epic, chore), not aliases","Never add extra dot segments to storage-class keys","Script config sets with a fixed key template","Check existing keys with bd config list as a shape reference"],"tags":["config","validation","storage-class"],"backgroundTag":"config-key-validation-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}