{"record":{"id":"fe305da93cb68f9a","repo":"MemPalace/mempalace","slug":"type-value-r-is-not-a-valid-event-type-lowercas","errorCode":null,"errorMessage":"type={value!r} is not a valid event type (lowercase letters, digits, '.', '_', '-'; max 64 chars)","messagePattern":"type=(.+?) is not a valid event type \\(lowercase letters, digits, '\\.', '_', '-'; max 64 chars\\)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mempalace/logstream.py","lineNumber":125,"sourceCode":"        if required:\n            raise ValueError(f\"{field_name} must be a non-empty string\")\n        return None\n    if not isinstance(value, str) or not value.strip():\n        raise ValueError(f\"{field_name} must be a non-empty string\")\n    value = strip_lone_surrogates(value.strip())\n    if len(value) > _MAX_ROUTING_LENGTH:\n        raise ValueError(f\"{field_name} exceeds maximum length of {_MAX_ROUTING_LENGTH} characters\")\n    if any(ord(ch) < 0x20 or ch == \"\\x7f\" for ch in value):\n        raise ValueError(f\"{field_name} contains control characters\")\n    return value\n\n\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:","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/logstream.py#L107-L143","documentation":"append_event (or any API taking an event type) rejected the `type` argument because it does not match the pattern ^[a-z0-9][a-z0-9_.-]{0,63}$. Event types are structured routing keys (e.g. 'task.request', 'patch.ready'), so the logstream enforces lowercase letters, digits, '.', '_', '-' with a 64-character maximum rather than accepting free-form strings. The value is stripped before matching, but whitespace inside, uppercase letters, '/', ':', and leading punctuation all fail.","triggerScenarios":"Calling ls.append_event(type='Task.Request', ...) (uppercase); type='task:request' (colon); type='task request' (space); type='.request' (leading dot fails the first-char class); type longer than 64 chars; type='' or None after strip; passing a filter type to list_events/wait_events with the same shape problems (both run _sanitize_event_type).","commonSituations":"Agents deriving event types from prose or file paths (e.g. 'Fix/Search' with a slash), copying type names from JSON keys with camelCase, or non-ASCII locales producing uppercase/Unicode variants. Also seen when a caller interpolates a version number like 'task.request.v2//beta'.","solutions":["Lowercase the value and restrict it to a-z, 0-9, '.', '_', '-' (e.g. 'task.request', 'patch.ready').","Check length: strip and count characters; keep it at 64 chars or fewer and start with a letter or digit.","Replace separators like ':', '/', ' ' with '.' or '-' before calling (e.g. 'Fix/Search' -> 'fix.search').","Validate against the same regex before the call: re.match(r'^[a-z0-9][a-z0-9_.-]{0,63}$', type)."],"exampleFix":"// before\nevt = ls.append_event(type=\"Task.Request:V2\", ...)\n// after\nevt = ls.append_event(type=\"task.request.v2\", ...)","handlingStrategy":"validation","validationCode":"import re\nEVENT_TYPE_RE = re.compile(r\"^[a-z0-9][a-z0-9_.-]{0,63}$\")\n\ndef valid_event_type(t):\n    return isinstance(t, str) and bool(EVENT_TYPE_RE.match(t.strip()))\n\n# before the call\nif not valid_event_type(evt_type):\n    evt_type = re.sub(r\"[^a-z0-9._-]\", \".\", evt_type.lower().strip())[:64]","typeGuard":"def is_event_type(value) -> bool:\n    return isinstance(value, str) and bool(__import__(\"re\").match(r\"^[a-z0-9][a-z0-9_.-]{0,63}$\", value.strip()))","tryCatchPattern":"try:\n    evt = ls.append_event(type=evt_type, ...)\nexcept ValueError as e:\n    if \"not a valid event type\" in str(e):\n        evt_type = re.sub(r\"[^a-z0-9._-]\", \".\", evt_type.lower().strip())[:64]\n        evt = ls.append_event(type=evt_type, ...)\n    else:\n        raise","preventionTips":["Centralize event-type construction in one helper that lowercases and slugifies.","Document the allowed pattern next to every producer integration point.","Add a unit test asserting your producer's emitted types match ^[a-z0-9][a-z0-9_.-]{0,63}$."],"tags":["validation","logstream","event-type","append-event"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}