MemPalace/mempalace · error · ValueError

--metadata must be a JSON object

Error message

--metadata must be a JSON object

What it means

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.

Source

Thrown at mempalace/cli.py:1514

        if file_arg == "-":
            return _read_stdin_exact()
        return Path(os.path.expanduser(file_arg)).read_bytes().decode("utf-8")
    if inline is not None:
        return inline
    return default


def _parse_metadata_arg(raw):
    import json

    if raw is None:
        return None
    try:
        value = json.loads(raw)
    except ValueError as exc:
        raise ValueError(f"--metadata is not valid JSON: {exc}") from None
    if not isinstance(value, dict):
        raise ValueError("--metadata must be a JSON object")
    return value


def _print_event_line(event):
    target = event["to_agent"] or "*"
    corr = f" corr={event['correlation_id']}" if event["correlation_id"] else ""
    status = f" [{event['status']}]" if event["status"] else ""
    arts = f" artifacts={len(event['artifact_ids'])}" if event["artifact_ids"] else ""
    body = event["body"].replace("\n", " ")
    if len(body) > 80:
        body = body[:77] + "..."
    body = f" :: {body}" if body else ""
    print(
        f"  {event['id']}  {event['created_at']}  {event['type']}  "
        f"{event['stream']}/{event['room']}  {event['from_agent']}->{target}"
        f"{status}{corr}{arts}{body}"
    )

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Wrap the value in a JSON object: use {"tags":[1,2]} instead of [1,2], or {"value":"tag"} instead of "tag"
  2. Check the command's documented metadata schema and mirror its key names

Example fix

# before
--metadata '["a","b"]'

# after
--metadata '{"tags":["a","b"]}'
Defensive patterns

Strategy: type-guard

Validate before calling

import json

parsed = json.loads(metadata_raw)
if not isinstance(parsed, dict):
    # wrap scalars/arrays in an object before passing --metadata
    metadata_raw = json.dumps({"value": parsed})

Type guard

def is_metadata_object(raw: str) -> bool:
    try:
        return isinstance(json.loads(raw), dict)
    except (ValueError, TypeError):
        return False

Try / catch

try:
    meta = _parse_metadata_arg(raw)
except ValueError as exc:
    if "must be a JSON object" in str(exc):
        meta = {"value": json.loads(raw)}  # known-good reshape for your schema
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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