can1357/oh-my-pi · error · ValueError

Unsupported content_type: {content_type!r}

Error message

Unsupported content_type: {content_type!r}

What it means

normalize_read_result() validates the optional 'content_type' field of a read-result dict against an allowlist: 'text/markdown', 'application/json', 'text/plain'. Any other MIME type (or a malformed value) raises ValueError, because the host only knows how to render/interpret these three content types. Set content_type to None (or omit it) to use the default.

Source

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

    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. Use one of the three allowed values exactly: 'text/markdown', 'application/json', or 'text/plain'
  2. Strip MIME parameters: 'text/plain; charset=utf-8'.split(';')[0].strip()
  3. Omit 'content_type' entirely (default) or serialize unsupported data to JSON/text before returning

Example fix

// before
return {'content': json.dumps(data), 'content_type': 'text/html'}
// after
return {'content': json.dumps(data), 'content_type': 'application/json'}
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = ('text/markdown', 'application/json', 'text/plain')
def check_content_type(ct):
    if ct is not None and ct not in ALLOWED:
        raise ValueError(f'content_type must be one of {ALLOWED}, got {ct!r}')
    return ct

Type guard

def is_allowed_content_type(ct) -> bool:
    return ct is None or ct in ('text/markdown', 'application/json', 'text/plain')

Try / catch

try:
    payload = normalize_read_result(result)
except ValueError as e:
    if 'content_type' in str(e):
        payload = normalize_read_result({**result, 'content_type': 'text/plain'})
    else:
        raise

Prevention

When it happens

Trigger: Returning {'content': '...', 'content_type': 'text/html'} or 'application/octet-stream' from a read handler; passing 'text/markdown; charset=utf-8' (with parameters) which fails exact membership; typos like 'text/md' or 'plain/text'.

Common situations: Handler echoing the source file's MIME type (images, CSV, HTML) instead of converting to an allowed type; charset suffix appended by a generic MIME-detection helper; drift after the library tightened the allowlist and old handlers still emit legacy types.

Related errors


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