MemPalace/mempalace · error · ValueError

kind={kind!r} is not one of: {allowed}

Error message

kind={kind!r} is not one of: {allowed}

What it means

put_artifact rejects the `kind` argument because it is not in ARTIFACT_KINDS = {'patch','file','log','json','note'}. Kinds are a controlled vocabulary describing payload shape (a diff, a whole file, a captured log, structured JSON, or a free note) so consumers can pick handlers; the allowed set is printed in the error.

Source

Thrown at mempalace/logstream.py:523

    def put_artifact(
        self,
        kind: str,
        content: str,
        created_by: str,
        metadata: dict = None,
    ) -> dict:
        """Store exact artifact content (v1: UTF-8 text only).

        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:

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Use one of: patch, file, log, json, note (lowercase, exact).
  2. Pick by payload shape: unified diff -> 'patch', full file -> 'file', structured data -> 'json', captured output -> 'log', prose -> 'note'.
  3. Guard the call site against an upstream kind vocabulary: map or reject before invoking put_artifact.

Example fix

// before
art = ls.put_artifact(kind="diff", content=diff_text, ...)
// after
art = ls.put_artifact(kind="patch", content=diff_text, ...)
Defensive patterns

Strategy: validation

Validate before calling

from mempalace.logstream import ARTIFACT_KINDS

def normalize_kind(kind):
    k = str(kind).strip().lower()
    aliases = {"diff": "patch", "text": "note", "data": "json", "output": "log"}
    return aliases.get(k, k)

kind = normalize_kind(raw_kind)
assert kind in ARTIFACT_KINDS, f"unsupported kind {raw_kind!r}"

Type guard

from mempalace.logstream import ARTIFACT_KINDS

def is_valid_kind(k) -> bool:
    return isinstance(k, str) and k in ARTIFACT_KINDS

Try / catch

try:
    art = ls.put_artifact(kind=kind, content=content, ...)
except ValueError as e:
    if "not one of" in str(e) and "kind=" in str(e):
        art = ls.put_artifact(kind="note", content=content, ...)  # generic fallback kind
    else:
        raise

Prevention

When it happens

Trigger: put_artifact(kind='diff', ...) (should be 'patch'); kind='text' (should be 'note' or 'file'); kind='JSON' (case-sensitive); kind=None or a non-string; kind='binary' for payloads v1 does not support.

Common situations: LLM agents guessing kind names from the content instead of the enum; version drift after new kinds were added/renamed; casing copied from documentation headings.

Related errors


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