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
- Split the content into multiple artifacts below the cap and link them from the event (artifact_ids accepts a list).
- Pre-check size: if len(content.encode('utf-8')) > ls.max_artifact_bytes: split or compress.
- 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
- Measure UTF-8 bytes, not characters, before creating large artifacts.
- Split monolithic diffs/logs into per-file artifacts so chunks stay far under 4 MiB.
- Keep max_artifact_bytes consistent across replicas that exchange artifacts.
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
- {field_name} is {size} bytes; maximum is {max_bytes} bytes
- metadata exceeds maximum size of {MAX_METADATA_BYTES} bytes
- kind={kind!r} is not one of: {allowed}
- content must be a non-empty string
- content contains null bytes
AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15).
Data as JSON: /api/errors/3a46b0b34733e2af.
Report an issue: GitHub.