MemPalace/mempalace · error · ValueError

content is {len(raw)} bytes; maximum is {self.max_artifact_b

Error message

content is {len(raw)} bytes; maximum is {self.max_artifact_bytes} bytes

What it means

The UTF-8 encoding of the artifact content exceeds max_artifact_bytes (default 4 MiB, settable via the Logstream constructor). The logstream stores artifacts verbatim with explicit limits and never truncates, so an oversized write is refused. The byte count in the message is the true encoded size, which matters for multi-byte scripts.

Source

Thrown at mempalace/logstream.py:532

        Returns the artifact record without echoing ``content`` back —
        callers already hold the content; readers use :meth:`get_artifact`.
        For ``kind=patch``, a ``warnings`` list is included when the diff
        looks unappliable (missing trailing newline, CRLF endings); the
        content itself is still stored verbatim.
        """
        if not isinstance(kind, str) or kind not in ARTIFACT_KINDS:
            allowed = ", ".join(sorted(ARTIFACT_KINDS))
            raise ValueError(f"kind={kind!r} is not one of: {allowed}")
        created_by = _sanitize_routing(created_by, "created_by")
        if not isinstance(content, str) or not content:
            raise ValueError("content must be a non-empty string")
        if "\x00" in content:
            raise ValueError("content contains null bytes")
        content = strip_lone_surrogates(content)
        raw = content.encode("utf-8")
        if len(raw) > self.max_artifact_bytes:
            raise ValueError(
                f"content is {len(raw)} bytes; maximum is {self.max_artifact_bytes} bytes"
            )
        metadata_json = _sanitize_metadata(metadata)

        artifact_id = _new_id("art")
        created_at = _utc_now_iso()
        digest = sha256(raw).hexdigest()

        with self._lock:
            conn = self._conn()
            with conn:
                conn.execute(
                    "INSERT INTO artifacts (id, kind, sha256, size_bytes, content,"
                    " created_by, created_at, metadata_json, origin_replica)"
                    " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
                    (
                        artifact_id,
                        kind,

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Split the content into multiple artifacts below the cap and link them from the event (artifact_ids accepts a list).
  2. Pre-check size: if len(content.encode('utf-8')) > ls.max_artifact_bytes: split or compress.
  3. If genuinely needed, raise the limit on every replica: Logstream(db_path=..., max_artifact_bytes=8*1024*1024).

Example fix

// before
art = ls.put_artifact(kind="patch", content=whole_repo_diff, ...)
// after
chunks = [whole_repo_diff[i:i+1_000_000] for i in range(0, len(whole_repo_diff), 1_000_000)]
arts = [ls.put_artifact(kind="patch", content=c, created_by="mac-codex") for c in chunks]
evt = ls.append_event(..., artifact_ids=[a["id"] for a in arts])
Defensive patterns

Strategy: validation

Validate before calling

def fits_artifact(ls, content: str) -> bool:
    return len(content.encode("utf-8")) <= ls.max_artifact_bytes

if not fits_artifact(ls, content):
    chunks = [content[i:i+1_000_000] for i in range(0, len(content), 1_000_000)]
    arts = [ls.put_artifact(kind=kind, content=c, created_by=who) for c in chunks]
    content, artifact_ids = None, [a["id"] for a in arts]

Type guard

def artifact_within_limit(ls, content) -> bool:
    return isinstance(content, str) and len(content.encode("utf-8")) <= ls.max_artifact_bytes

Try / catch

try:
    art = ls.put_artifact(kind=kind, content=content, ...)
except ValueError as e:
    if "maximum is" in str(e) and "bytes" in str(e):
        mid = len(content) // 2
        a1 = ls.put_artifact(kind=kind, content=content[:mid], ...)
        a2 = ls.put_artifact(kind=kind, content=content[mid:], ...)
        art = None  # reference both ids from the event
    else:
        raise

Prevention

When it happens

Trigger: put_artifact(kind='file', content=huge_file_text) over 4,194,304 bytes; a large patch generated across a whole repo; UTF-8 text whose character count is under 4M but byte count over it; replicas constructed with different max_artifact_bytes values.

Common situations: Whole-repo diffs or bundled logs attached as one artifact; no chunking strategy in the producer; the limit lowered in config while old tooling still emits monolith artifacts.

Related errors


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