{"record":{"id":"c393fcabd34c905c","repo":"MemPalace/mempalace","slug":"status-value-r-is-not-one-of-allowed","errorCode":null,"errorMessage":"status={value!r} is not one of: {allowed}","messagePattern":"status=(.+?) is not one of: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mempalace/logstream.py","lineNumber":137,"sourceCode":"\ndef _sanitize_event_type(value) -> str:\n    if not isinstance(value, str) or not value.strip():\n        raise ValueError(\"type must be a non-empty string\")\n    value = value.strip()\n    if not _EVENT_TYPE_RE.match(value):\n        raise ValueError(\n            f\"type={value!r} is not a valid event type \"\n            \"(lowercase letters, digits, '.', '_', '-'; max 64 chars)\"\n        )\n    return value\n\n\ndef _sanitize_status(value) -> Optional[str]:\n    if value is None or value == \"\":\n        return None\n    if not isinstance(value, str) or value not in EVENT_STATUSES:\n        allowed = \", \".join(sorted(EVENT_STATUSES))\n        raise ValueError(f\"status={value!r} is not one of: {allowed}\")\n    return value\n\n\ndef _sanitize_body(value, max_bytes: int, field_name: str = \"body\") -> str:\n    \"\"\"Validate verbatim payload text. Empty is allowed; ``None`` becomes ''.\"\"\"\n    if value is None:\n        return \"\"\n    if not isinstance(value, str):\n        raise ValueError(f\"{field_name} must be a string\")\n    if \"\\x00\" in value:\n        raise ValueError(f\"{field_name} contains null bytes\")\n    value = strip_lone_surrogates(value)\n    size = len(value.encode(\"utf-8\"))\n    if size > max_bytes:\n        raise ValueError(f\"{field_name} is {size} bytes; maximum is {max_bytes} bytes\")\n    return value\n\n","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/logstream.py#L119-L155","documentation":"The `status` field of append_event/ack_event must be one of the fixed lifecycle set EVENT_STATUSES = {'open','claimed','ready','applied','blocked','failed','superseded'} (or None/'' to omit). Any other string — including near-misses like 'done', 'OK', 'claimed ' with a space — is rejected with the allowed list echoed in the message. Statuses are a controlled vocabulary so agents can filter reliably.","triggerScenarios":"append_event(status='done'), status='In Progress', status='claimed!' from an LLM-generated payload, or ack_event(status='ok'). Passing a non-string such as status=0 or status=True also triggers it (isinstance check comes second).","commonSituations":"LLM agents freestyle a status word instead of the enum; callers mapping tickets from external trackers (Jira 'In Review', 'Closed') directly into the logstream; casing or spelling drift between producer versions.","solutions":["Use one of the exact allowed values: open, claimed, ready, applied, blocked, failed, superseded.","Map external statuses to the enum before calling (e.g. 'Closed' -> 'applied', 'In Review' -> 'claimed').","Pass status=None or omit it when there is no lifecycle state to record."],"exampleFix":"// before\nls.append_event(type=\"task.request\", status=\"Done\", ...)\n// after\nls.append_event(type=\"task.request\", status=\"applied\", ...)","handlingStrategy":"validation","validationCode":"from mempalace.logstream import EVENT_STATUSES\n\ndef normalize_status(s):\n    if s is None or s == \"\":\n        return None\n    s = str(s).strip().lower()\n    aliases = {\"done\": \"applied\", \"ok\": \"applied\", \"in_progress\": \"claimed\", \"closed\": \"applied\"}\n    return aliases.get(s, s) if s in EVENT_STATUSES or s in aliases else None\n\nstatus = normalize_status(raw_status)\nif raw_status and status is None:\n    raise ValueError(f\"unmappable status {raw_status!r}\")","typeGuard":"from mempalace.logstream import EVENT_STATUSES\n\ndef is_valid_status(s) -> bool:\n    return s is None or s == \"\" or (isinstance(s, str) and s in EVENT_STATUSES)","tryCatchPattern":"try:\n    evt = ls.append_event(..., status=status)\nexcept ValueError as e:\n    if \"not one of\" in str(e) and \"status=\" in str(e):\n        evt = ls.append_event(..., status=None)  # drop rather than fail the event\n    else:\n        raise","preventionTips":["Import EVENT_STATUSES from mempalace.logstream and validate against it instead of hardcoding the list.","Map external tracker statuses to the enum at the adapter layer, never inside event-writing code.","Reject unmappable statuses loudly at ingestion so bad vocabularies surface early."],"tags":["validation","logstream","status","enum"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}