{"record":{"id":"ea10da0ddbb3f36e","repo":"MemPalace/mempalace","slug":"kind-kind-r-is-not-one-of-allowed","errorCode":null,"errorMessage":"kind={kind!r} is not one of: {allowed}","messagePattern":"kind=(.+?) is not one of: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mempalace/logstream.py","lineNumber":523,"sourceCode":"\n    def put_artifact(\n        self,\n        kind: str,\n        content: str,\n        created_by: str,\n        metadata: dict = None,\n    ) -> dict:\n        \"\"\"Store exact artifact content (v1: UTF-8 text only).\n\n        Returns the artifact record without echoing ``content`` back —\n        callers already hold the content; readers use :meth:`get_artifact`.\n        For ``kind=patch``, a ``warnings`` list is included when the diff\n        looks unappliable (missing trailing newline, CRLF endings); the\n        content itself is still stored verbatim.\n        \"\"\"\n        if not isinstance(kind, str) or kind not in ARTIFACT_KINDS:\n            allowed = \", \".join(sorted(ARTIFACT_KINDS))\n            raise ValueError(f\"kind={kind!r} is not one of: {allowed}\")\n        created_by = _sanitize_routing(created_by, \"created_by\")\n        if not isinstance(content, str) or not content:\n            raise ValueError(\"content must be a non-empty string\")\n        if \"\\x00\" in content:\n            raise ValueError(\"content contains null bytes\")\n        content = strip_lone_surrogates(content)\n        raw = content.encode(\"utf-8\")\n        if len(raw) > self.max_artifact_bytes:\n            raise ValueError(\n                f\"content is {len(raw)} bytes; maximum is {self.max_artifact_bytes} bytes\"\n            )\n        metadata_json = _sanitize_metadata(metadata)\n\n        artifact_id = _new_id(\"art\")\n        created_at = _utc_now_iso()\n        digest = sha256(raw).hexdigest()\n\n        with self._lock:","sourceCodeStart":505,"sourceCodeEnd":541,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/logstream.py#L505-L541","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use one of: patch, file, log, json, note (lowercase, exact).","Pick by payload shape: unified diff -> 'patch', full file -> 'file', structured data -> 'json', captured output -> 'log', prose -> 'note'.","Guard the call site against an upstream kind vocabulary: map or reject before invoking put_artifact."],"exampleFix":"// before\nart = ls.put_artifact(kind=\"diff\", content=diff_text, ...)\n// after\nart = ls.put_artifact(kind=\"patch\", content=diff_text, ...)","handlingStrategy":"validation","validationCode":"from mempalace.logstream import ARTIFACT_KINDS\n\ndef normalize_kind(kind):\n    k = str(kind).strip().lower()\n    aliases = {\"diff\": \"patch\", \"text\": \"note\", \"data\": \"json\", \"output\": \"log\"}\n    return aliases.get(k, k)\n\nkind = normalize_kind(raw_kind)\nassert kind in ARTIFACT_KINDS, f\"unsupported kind {raw_kind!r}\"","typeGuard":"from mempalace.logstream import ARTIFACT_KINDS\n\ndef is_valid_kind(k) -> bool:\n    return isinstance(k, str) and k in ARTIFACT_KINDS","tryCatchPattern":"try:\n    art = ls.put_artifact(kind=kind, content=content, ...)\nexcept ValueError as e:\n    if \"not one of\" in str(e) and \"kind=\" in str(e):\n        art = ls.put_artifact(kind=\"note\", content=content, ...)  # generic fallback kind\n    else:\n        raise","preventionTips":["Import ARTIFACT_KINDS and validate/normalize at the edge where external kind vocabularies enter.","Pin kind choice to payload shape (diff->patch, file->file, captured output->log, structured->json, prose->note)."],"tags":["validation","logstream","artifact","enum"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}