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

  1. Skip the write entirely when there is no content: `if not content or not content.strip(): return`
  2. Fix the extraction/hook step that produced empty content instead of forcing a write
  3. 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

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


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/2e30e070b3bce84d. Report an issue: GitHub.