{"record":{"id":"c7301550a4c07aac","repo":"MemPalace/mempalace","slug":"field-name-must-be-a-non-empty-string-c73015","errorCode":null,"errorMessage":"{field_name} must be a non-empty string","messagePattern":"(.+?) must be a non-empty string","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mempalace/logstream.py","lineNumber":108,"sourceCode":"\n    Uniqueness comes from the random suffix; ordering guarantees come\n    from the rowid, so clock skew between writers cannot reorder or\n    collide events.\n    \"\"\"\n    stamp = datetime.now(timezone.utc).strftime(\"%Y%m%dT%H%M%S\")\n    return f\"{prefix}_{stamp}_{secrets.token_hex(6)}\"\n\n\ndef _sanitize_routing(value, field_name: str, required: bool = True) -> Optional[str]:\n    \"\"\"Validate a short routing field (stream, room, agent, correlation_id).\n\n    Streams may contain ``/`` (``project/mempalace``), so this is looser\n    than ``config.sanitize_name`` — but null bytes, control characters,\n    and over-length values are still rejected.\n    \"\"\"\n    if value is None or value == \"\":\n        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 \"","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/logstream.py#L90-L126","documentation":"ValueError raised by logstream's _sanitize_routing() when a required routing field (stream, room, agent, correlation_id) is None or the empty string. Required routing fields must carry a value before the stricter string/length/control-character checks run.","triggerScenarios":"Calling the event-emission API with stream=None or correlation_id=\"\" while the field is required (required=True, the default); a wrapper defaulting an argument to None instead of generating a value.","commonSituations":"Forgetting to pass correlation_id when correlating events; optional-looking kwargs that are actually required; code paths where the caller computes the stream name and the computation returns None.","solutions":["Supply a non-empty value for the named field","If the field is genuinely optional in your flow, pass required=False so None/'' maps to None","Generate correlation ids up front (the module provides stamp+token helpers) instead of passing None"],"exampleFix":"# before\nevents.emit(type=\"agent.turn.end\", stream=\"\", room=\"r1\", agent=\"a1\")  # ValueError: stream must be a non-empty string\n\n# after\nevents.emit(type=\"agent.turn.end\", stream=\"project/mempalace\", room=\"r1\", agent=\"a1\")","handlingStrategy":"validation","validationCode":"def require_routing(value, field):\n    if value is None or value == \"\":\n        raise ValueError(f\"{field} must be a non-empty string\")\n    return value\n\nstream = require_routing(stream, \"stream\")\ncorrelation_id = require_routing(correlation_id or new_id(), \"correlation_id\")","typeGuard":null,"tryCatchPattern":"try:\n    events.emit(type=t, stream=s, room=r, agent=a)\nexcept ValueError as e:\n    if \"must be a non-empty string\" in str(e):\n        # fill in the missing field from context and retry\n        ...\n    raise","preventionTips":["Generate correlation ids eagerly when a logical operation starts","Make routing fields mandatory keyword arguments in your own wrappers","Fail fast on missing stream/room at workflow start, not per event"],"tags":["logstream","validation","routing","required-field"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}