rohitg00/ai-engineering-from-scratch · error · ProtocolViolation

invalid JSON-RPC response envelope

Error message

invalid JSON-RPC response envelope

What it means

validate_response checks every JSON-RPC response envelope before anything else: the parsed body must be a dict and carry jsonrpc == "2.0". This fires when the HTTP body was not valid JSON-RPC at all (wrong transport framing, plain-text error page, or a missing/misspelled jsonrpc version field), so no further response validation can proceed.

Solutions

  1. Log the raw response body and content type to see what the server actually returned
  2. Ensure the client parses the body as JSON before passing it to validate_response
  3. Fix the server to emit a JSON object with "jsonrpc": "2.0"
  4. Check for a proxy or gateway intercepting the request and returning an HTML error page
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/code/main.py:389 when the library encounters an invalid state.

Common situations: See trigger scenarios.

Understand the failure class


AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26). Data as JSON: /api/errors/3795ad581f3449d7. Report an issue: GitHub.

Appendix: source

Thrown at phases/13-tools-and-protocols/31-mcp-conformance-versioning-and-operations/code/main.py:389


@dataclass(frozen=True)
class CaseResult:
    name: str
    passed: bool
    detail: str
    evidence_digest: str


def validate_response(
    request: dict[str, Any],
    status: int,
    response: dict[str, Any],
    era: str,
    capabilities: set[str],
) -> None:
    if not isinstance(response, dict) or response.get("jsonrpc") != "2.0":
        raise ProtocolViolation("invalid JSON-RPC response envelope")
    request_id = request.get("id")
    response_id = response.get("id")
    if type(response_id) is not type(request_id) or response_id != request_id:
        raise ProtocolViolation("response id does not exactly match request id")
    has_result = "result" in response
    has_error = "error" in response
    if has_result == has_error:
        raise ProtocolViolation("response must contain exactly one of result or error")
    if has_result:
        if status != 200:
            raise ProtocolViolation("successful JSON-RPC result requires HTTP 200")
        validate_result(response["result"], era, capabilities)
        validate_method_result(request["method"], response["result"])
        return

    error = response["error"]
    if not isinstance(error, dict):
        raise ProtocolViolation("JSON-RPC error must be an object")

View on GitHub (pinned to 39ea8a1c6d)