can1357/oh-my-pi · error · ValueError

HostUriReadResult requires a 'content' field

Error message

HostUriReadResult requires a 'content' field

What it means

When normalize_read_result() receives a dict from a read handler, that dict must include a 'content' key — it is the only field the host_uri_result payload requires. A dict without 'content' (e.g. only 'notes' or 'content_type') raises ValueError. String returns are exempt because they are auto-wrapped into {'content': ...}.

Source

Thrown at python/omp-rpc/src/omp_rpc/host_uris.py:110

    )


def normalize_read_result(value: HostUriReadValue) -> JsonObject:
    """Convert a handler's `read` return into the wire-frame fields.

    Returns a dict suitable for spreading into a `host_uri_result` payload.
    """

    if isinstance(value, str):
        return {"content": value}
    if not isinstance(value, dict):
        raise TypeError(
            "Host URI read handlers must return a string or a HostUriReadResult mapping"
        )

    payload: JsonObject = {}
    if "content" not in value:
        raise ValueError("HostUriReadResult requires a 'content' field")
    payload["content"] = str(value["content"])

    content_type = value.get("content_type")
    if content_type is not None:
        if content_type not in ("text/markdown", "application/json", "text/plain"):
            raise ValueError(f"Unsupported content_type: {content_type!r}")
        payload["contentType"] = content_type

    notes = value.get("notes")
    if notes is not None:
        payload["notes"] = [str(item) for item in notes]

    if "immutable" in value:
        payload["immutable"] = bool(value["immutable"])

    return payload

View on GitHub (pinned to 9690622007)

Solutions

  1. Always include 'content' in the returned dict: {'content': str(value), ...} even when it is an empty string or an explanatory message
  2. If there is nothing to return, return a string like 'resource not found' instead of a bare dict
  3. Rename alternate keys ('text', 'body', 'data') to 'content' in the handler

Example fix

// before
def read(path):
    if not exists(path):
        return {'notes': ['missing']}
// after
def read(path):
    if not exists(path):
        return {'content': '', 'notes': ['resource not found']}
Defensive patterns

Strategy: type-guard

Validate before calling

def check_read_dict(value: dict) -> dict:
    if 'content' not in value:
        raise ValueError("read result dict requires a 'content' field")
    return value

Type guard

def has_content(value) -> bool:
    return isinstance(value, dict) and 'content' in value

Try / catch

try:
    payload = normalize_read_result(handler_result)
except (TypeError, ValueError) as e:
    logger.error('invalid read result: %s', e)
    payload = {'content': ''}

Prevention

When it happens

Trigger: Returning a dict like {'notes': ['empty'], 'content_type': 'text/plain'} from a read handler and forgetting 'content'; building the result dict conditionally so 'content' is omitted on an empty/error branch; passing an already-parsed JSON object that uses a different key name like 'text' or 'body'.

Common situations: Handlers that return metadata-only dicts for edge cases (missing file, empty resource), key renamed during a refactor ('text' -> 'content'), or spreading a config dict that happens to lack 'content'.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/f305452c7813402d. Report an issue: GitHub.