MemPalace/mempalace · error · ValueError
content must be a non-empty string
Error message
content must be a non-empty string
What it means
Raised by sanitize_content() when drawer/diary content is not a string, or is empty/whitespace-only. Content is stored verbatim, so an empty payload would create a drawer that exists but holds nothing — the validator rejects it at the boundary. All drawer/diary write paths (CLI, MCP tools) route through this check.
Source
Thrown at mempalace/config.py:213
return value
def sanitize_iso_date(value, field_name: str = "date"):
"""Backward-compatible wrapper for ISO temporal validation.
Historically this accepted only full dates. It now also accepts canonical
UTC datetimes, but the old name is kept so existing imports continue to
work.
"""
return sanitize_iso_temporal(value, field_name)
def sanitize_content(value: str, max_length: int = 100_000) -> str:
"""Validate drawer/diary content length."""
if not isinstance(value, str) or not value.strip():
raise ValueError("content must be a non-empty string")
if len(value) > max_length:
raise ValueError(f"content exceeds maximum length of {max_length} characters")
if "\x00" in value:
raise ValueError("content contains null bytes")
return strip_lone_surrogates(value)
DEFAULT_PALACE_PATH = os.path.expanduser("~/.mempalace/palace")
DEFAULT_COLLECTION_NAME = "mempalace_drawers"
DEFAULT_BACKEND = "chroma"
DEFAULT_MILVUS_CONSISTENCY_LEVEL = "Strong"
_MILVUS_CONSISTENCY_LEVELS = {
"strong": "Strong",
"session": "Session",
"bounded": "Bounded",
"eventually": "Eventually",
}
View on GitHub (pinned to 06cb6987f0)
Solutions
- Skip the write entirely when there is no content: `if not content or not content.strip(): return`
- Fix the extraction/hook step that produced empty content instead of forcing a write
- Pass content as a str; encode/decode binary input explicitly before the call
Example fix
# before
save_drawer(wing, room, transcript_text) # may be ""
# after
if transcript_text and transcript_text.strip():
save_drawer(wing, room, transcript_text) Defensive patterns
Strategy: validation
Validate before calling
# Skip degenerate writes instead of letting the library reject them:
if not isinstance(content, str) or not content.strip():
return # nothing to store verbatim Type guard
def is_nonempty_content(value) -> bool:
return isinstance(value, str) and bool(value.strip()) Try / catch
try:
safe = sanitize_content(content)
except ValueError as exc:
if "non-empty" in str(exc):
return # deliberately skip empty drawers
raise Prevention
- Make hook/extraction scripts no-op on empty text instead of forcing saves
- Check transcripts for blank extraction results before writing
- Pass content as str; never forward raw bytes
When it happens
Trigger: Calling a drawer/diary write API with content=None, content=123, or "" / " " — e.g. a hook script passing an empty transcript buffer, or an MCP tool call where the content argument was omitted.
Common situations: Stop-hooks saving a session whose extracted text came back empty; scripts forwarding an unset variable; whitespace-only content from a failed extraction step; JSON payloads with a missing content key defaulting to None.
Related errors
- content exceeds maximum length of {max_length} characters
- content contains null bytes
- pass inline text or a file, not both
- --metadata is not valid JSON: {exc}
- --metadata must be a JSON object
AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15).
Data as JSON: /api/errors/2e30e070b3bce84d.
Report an issue: GitHub.