MemPalace/mempalace · error · ValueError
{field_name} must be a non-empty string
Error message
{field_name} must be a non-empty string What it means
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.
Source
Thrown at mempalace/logstream.py:108
Uniqueness comes from the random suffix; ordering guarantees come
from the rowid, so clock skew between writers cannot reorder or
collide events.
"""
stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%S")
return f"{prefix}_{stamp}_{secrets.token_hex(6)}"
def _sanitize_routing(value, field_name: str, required: bool = True) -> Optional[str]:
"""Validate a short routing field (stream, room, agent, correlation_id).
Streams may contain ``/`` (``project/mempalace``), so this is looser
than ``config.sanitize_name`` — but null bytes, control characters,
and over-length values are still rejected.
"""
if value is None or value == "":
if required:
raise ValueError(f"{field_name} must be a non-empty string")
return None
if not isinstance(value, str) or not value.strip():
raise ValueError(f"{field_name} must be a non-empty string")
value = strip_lone_surrogates(value.strip())
if len(value) > _MAX_ROUTING_LENGTH:
raise ValueError(f"{field_name} exceeds maximum length of {_MAX_ROUTING_LENGTH} characters")
if any(ord(ch) < 0x20 or ch == "\x7f" for ch in value):
raise ValueError(f"{field_name} contains control characters")
return value
def _sanitize_event_type(value) -> str:
if not isinstance(value, str) or not value.strip():
raise ValueError("type must be a non-empty string")
value = value.strip()
if not _EVENT_TYPE_RE.match(value):
raise ValueError(
f"type={value!r} is not a valid event type "View on GitHub (pinned to 06cb6987f0)
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
Example fix
# before events.emit(type="agent.turn.end", stream="", room="r1", agent="a1") # ValueError: stream must be a non-empty string # after events.emit(type="agent.turn.end", stream="project/mempalace", room="r1", agent="a1")
Defensive patterns
Strategy: validation
Validate before calling
def require_routing(value, field):
if value is None or value == "":
raise ValueError(f"{field} must be a non-empty string")
return value
stream = require_routing(stream, "stream")
correlation_id = require_routing(correlation_id or new_id(), "correlation_id") Try / catch
try:
events.emit(type=t, stream=s, room=r, agent=a)
except ValueError as e:
if "must be a non-empty string" in str(e):
# fill in the missing field from context and retry
...
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- {field_name} exceeds maximum length of {_MAX_ROUTING_LENGTH}
- type must be a non-empty string
- {field_name} contains control characters
- type={value!r} is not a valid event type (lowercase letters,
- status={value!r} is not one of: {allowed}
AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15).
Data as JSON: /api/errors/c7301550a4c07aac.
Report an issue: GitHub.