{"record":{"id":"b9dec28c6a604a63","repo":"mvanhorn/last30days-skill","slug":"unknown-audience-register-name-r-choose-one-of","errorCode":null,"errorMessage":"unknown audience register {name!r}; choose one of: {choices}","messagePattern":"unknown audience register (.+?); choose one of: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/last30days/scripts/lib/registers.py","lineNumber":131,"sourceCode":"        },\n    ),\n    # ELI5 historically changed only the agent's prose. Keep the renderer\n    # descriptor identical to default and express its voice in SKILL.md.\n    \"eli5\": _preset(\"eli5\"),\n}\n\nREGISTER_NAMES = tuple(_REGISTERS)\n\n\ndef get_register(name: str | None = None) -> AudienceRegister:\n    \"\"\"Return a named register, rejecting unsupported/free-form templates.\"\"\"\n\n    normalized = (name or \"default\").strip().lower()\n    try:\n        return _REGISTERS[normalized]\n    except KeyError as exc:\n        choices = \", \".join(REGISTER_NAMES)\n        raise ValueError(\n            f\"unknown audience register {name!r}; choose one of: {choices}\"\n        ) from exc\n","sourceCodeStart":113,"sourceCodeEnd":134,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/registers.py#L113-L134","documentation":"ValueError from get_register rejecting any audience-register name not present in the _REGISTERS table (normalized by strip+lower; None defaults to 'default'). The error enumerates REGISTER_NAMES so callers know the closed set - free-form template names are deliberately unsupported.","triggerScenarios":"get_register(name) with a typo ('technical', 'eli5 '), an invented register ('pirate'), or the wrong casing handled but trailing junk not ('ELI5 ' is fine after normalization, 'eli-5' is not). The KeyError from the dict lookup is chained as __cause__.","commonSituations":"User-supplied register strings from CLI flags or harness prompts; config files written before a register was renamed/removed; scripts hardcoding register names that drifted across versions.","solutions":["Use one of the names listed in the error message / REGISTER_NAMES constant","Validate user input against REGISTER_NAMES before calling get_register","Normalize input with .strip().lower() first, since normalization happens inside but junk characters still fail"],"exampleFix":"# before\nreg = get_register(\"hackernews\")  # ValueError\n\n# after\nfrom lib.registers import REGISTER_NAMES\nname = input().strip().lower()\nif name not in REGISTER_NAMES:\n    name = \"default\"\nreg = get_register(name)","handlingStrategy":"validation","validationCode":"from lib.registers import REGISTER_NAMES\n\nname = (user_input or \"default\").strip().lower()\nif name not in REGISTER_NAMES:\n    name = \"default\"","typeGuard":"def is_known_register(name: str | None) -> bool:\n    return (name or \"default\").strip().lower() in REGISTER_NAMES","tryCatchPattern":"try:\n    reg = get_register(name)\nexcept ValueError as e:\n    if \"unknown audience register\" in str(e):\n        reg = get_register(\"default\")  # explicit, logged fallback\n    raise","preventionTips":["Offer REGISTER_NAMES as the only choices in UIs (dropdown, not free text)","Validate against the constant, not a hardcoded copy that can drift","Normalize with strip().lower() before comparing"],"tags":["registers","validation","valueerror","configuration"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}