{"record":{"id":"6c5ab0efbe006a43","repo":"MemPalace/mempalace","slug":"metadata-must-be-a-json-object","errorCode":null,"errorMessage":"--metadata must be a JSON object","messagePattern":"--metadata must be a JSON object","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mempalace/cli.py","lineNumber":1514,"sourceCode":"        if file_arg == \"-\":\n            return _read_stdin_exact()\n        return Path(os.path.expanduser(file_arg)).read_bytes().decode(\"utf-8\")\n    if inline is not None:\n        return inline\n    return default\n\n\ndef _parse_metadata_arg(raw):\n    import json\n\n    if raw is None:\n        return None\n    try:\n        value = json.loads(raw)\n    except ValueError as exc:\n        raise ValueError(f\"--metadata is not valid JSON: {exc}\") from None\n    if not isinstance(value, dict):\n        raise ValueError(\"--metadata must be a JSON object\")\n    return value\n\n\ndef _print_event_line(event):\n    target = event[\"to_agent\"] or \"*\"\n    corr = f\" corr={event['correlation_id']}\" if event[\"correlation_id\"] else \"\"\n    status = f\" [{event['status']}]\" if event[\"status\"] else \"\"\n    arts = f\" artifacts={len(event['artifact_ids'])}\" if event[\"artifact_ids\"] else \"\"\n    body = event[\"body\"].replace(\"\\n\", \" \")\n    if len(body) > 80:\n        body = body[:77] + \"...\"\n    body = f\" :: {body}\" if body else \"\"\n    print(\n        f\"  {event['id']}  {event['created_at']}  {event['type']}  \"\n        f\"{event['stream']}/{event['room']}  {event['from_agent']}->{target}\"\n        f\"{status}{corr}{arts}{body}\"\n    )\n","sourceCodeStart":1496,"sourceCodeEnd":1532,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/cli.py#L1496-L1532","documentation":"Raised by _parse_metadata_arg() when the --metadata value parses as valid JSON but is not an object (dict). Metadata must be a JSON object because it is attached to stored records as key/value pairs; arrays, strings, numbers, booleans, or null are all rejected even though they are valid JSON.","triggerScenarios":"Passing --metadata '[1,2]' (array), --metadata '\"tag\"' (bare string), --metadata '42', --metadata 'null', or --metadata 'true' — json.loads succeeds but isinstance(value, dict) is False.","commonSituations":"Users pasting a JSON array of tags instead of an object like {\"tags\":[...]}; wrapping a scalar because a schema example suggested a bare value; omitting the outer braces.","solutions":["Wrap the value in a JSON object: use {\"tags\":[1,2]} instead of [1,2], or {\"value\":\"tag\"} instead of \"tag\"","Check the command's documented metadata schema and mirror its key names"],"exampleFix":"# before\n--metadata '[\"a\",\"b\"]'\n\n# after\n--metadata '{\"tags\":[\"a\",\"b\"]}'","handlingStrategy":"type-guard","validationCode":"import json\n\nparsed = json.loads(metadata_raw)\nif not isinstance(parsed, dict):\n    # wrap scalars/arrays in an object before passing --metadata\n    metadata_raw = json.dumps({\"value\": parsed})","typeGuard":"def is_metadata_object(raw: str) -> bool:\n    try:\n        return isinstance(json.loads(raw), dict)\n    except (ValueError, TypeError):\n        return False","tryCatchPattern":"try:\n    meta = _parse_metadata_arg(raw)\nexcept ValueError as exc:\n    if \"must be a JSON object\" in str(exc):\n        meta = {\"value\": json.loads(raw)}  # known-good reshape for your schema\n    else:\n        raise","preventionTips":["Always start --metadata with '{' and end with '}'","Put arrays inside an object: {\"tags\": [...]}, never a bare [...]","Document the expected metadata keys next to each command in your scripts"],"tags":["cli","json","validation","metadata","mempalace"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}