skip to content

JSON-RPC 2.0 calls itself transport agnostic — what does that leave a protocol carrying it over HTTP or a byte stream to define?

level: seniorimportance: should knowfreq 12%

answer

  1. data structures, not a wire
  2. no status codes, no framing
  3. either end may act as Server
  4. ids distinct among calls in flight
  5. the carrying protocol fills the gaps

basics

~20 s

JSON-RPC 2.0 defines only objects and their processing rules. A protocol carrying it must define message framing on a stream, any HTTP mapping (method, status codes, what a notification gets), which side may send requests, and cancellation or timeouts.

solid answer

~50 s

The specification defines data structures and the rules for processing them, and says they work within one process, over sockets, over HTTP or in any message-passing environment — then stops. Everything a wire needs falls to whatever carries the objects: how a reader finds where one JSON text ends on a byte stream; over HTTP, which method and status codes to use, and what HTTP response a notification or an all-notification batch gets when JSON-RPC itself sends nothing; whether both ends may act as Server on one connection, which the specification notes is possible and declines to address; how ids stay distinct among requests in flight; and how calls are cancelled or timed out. Protocols such as LSP, MCP and Ethereum node APIs each answer these in their own documents. Whatever the transport does, the JSON-RPC outcome lives in the Response body's `result` or `error`.

go deeper

for a junior

Recall that JSON-RPC 2.0 defines message objects only and runs over HTTP, sockets or anything else that can carry them.

for a middle

List what the specification leaves undefined — framing, HTTP status codes, roles, cancellation — and explain how a receiver tells a Request from a Response by its members.

for a senior

Read a protocol built on JSON-RPC and find the gaps it failed to fill, such as no framing rule, no cancellation, or an HTTP status policy that clients will misread.

for a principal

Decide what an organisation must specify around JSON-RPC before two teams can implement the same protocol independently, and which of those choices to standardise across every service.

## What the specification defines — and where it stops The JSON-RPC 2.0 specification describes itself as **transport agnostic**: its concepts "can be used within the same process, over sockets, over http, or in many various message passing environments". What it actually defines is narrow: - the **Request**, **Notification**, **Response** and **Error** objects; - the **batch** Array and its reply rules; - the **reserved error codes** and the reserved `rpc.` method prefix; - the roles: a **Client** originates Requests and handles Responses, a **Server** does the reverse. It defines no framing, no HTTP binding, no connection life cycle, no authentication, no cancellation and no timeout. That is a deliberate scope, and it is why the same objects can sit under very different protocols — the Language Server Protocol, the Model Context Protocol and Ethereum node APIs among them — each of which supplies the missing parts in its own specification. ## The gaps a carrying protocol must fill | Concern | What JSON-RPC 2.0 says | Who decides | |---|---|---| | Message boundaries on a byte stream | Nothing | The carrying protocol | | HTTP method, status codes, headers | Nothing | The carrying protocol or the implementation | | What HTTP returns for a notification | Nothing; JSON-RPC sends no Response | The carrying protocol or the implementation | | Which side may send Requests | One implementation may fill both roles; "this specification does not address that layer of complexity" | The carrying protocol | | Uniqueness of ids | Nothing beyond "established by the Client" | The Client, as the carrying protocol requires | | Cancellation and timeouts | Nothing | The carrying protocol | | Authentication and sessions | Nothing | The carrying protocol or the deployment | ## Over HTTP JSON-RPC 2.0 has no HTTP section at all. (JSON-RPC 1.0 had one, describing serialized objects sent in HTTP POST bodies; 2.0 dropped it along with 1.0's stream rules.) The consequences are concrete: - **Status codes are not specified.** No code is required for `-32601` or any other error. Some implementations answer 200 and let the `error` member carry the failure; others map selected errors onto HTTP statuses. Neither is a JSON-RPC rule. - **The body is authoritative.** The JSON-RPC outcome of a call is the Response's `result` or `error`. An HTTP status is at most an extra signal the carrying protocol chooses to add, and a client that reads only the status misses what the specification actually says happened. - **Silence needs an HTTP shape.** HTTP pairs each request with a response, but JSON-RPC sends nothing for a notification or an all-notification batch, so the carrying protocol must decide what that HTTP response looks like. ## Over a bidirectional stream On a socket or a pair of pipes, both ends can send at any time, and the specification allows one implementation to act as Client and Server at once. Three things then need care: 1. **Framing.** A byte stream has no message boundaries, and JSON-RPC defines none. The carrying protocol picks a technique — a length header in front of each message, or a delimiter between messages — and every reader must follow it. 2. **Telling Requests from Responses.** The objects themselves say which is which: a Request has a `method` member (and an `id` unless it is a notification), while a Response has `result` or `error` and no `method`. 3. **Two id spaces.** Each side establishes the ids of the Requests it sends, and matches incoming Responses only against those. Both sides may use 1, 2, 3 without collision, because a Response always travels back to the side that sent the Request. ## Correlation, cancellation and lost responses The specification ties a Response to a Request by `id` and says nothing about how long to wait. Nor does it say ids must be unique, but a Client that has two requests in flight under one `id` cannot tell their Responses apart. A stuck call cannot be cancelled by anything JSON-RPC defines; protocols that need cancellation define it themselves, for example as a notification naming the `id` to abandon. Whether a call whose Response never arrived may be sent again is a question of invocation semantics under failure, not something this specification addresses. ## A checklist for a new protocol on JSON-RPC 2.0 1. Name the transport and its framing. 2. If HTTP is involved, fix the method, the media type, the status-code policy and what a notification gets back. 3. State which side may send Requests and whether both may. 4. Specify id rules: type, uniqueness among requests in flight, and whether null is forbidden. 5. Define cancellation, timeouts and the connection's start and end. 6. Define the application error codes, outside the reserved band. A protocol that answers all six is complete enough to implement twice and interoperate; one that answers only "it is JSON-RPC" is not.

  • Over HTTP, which status code does the JSON-RPC 2.0 specification require for a -32601 Method not found response?
    None. The 2.0 specification defines no HTTP mapping, so status codes are the carrying protocol's or the implementation's choice. Some answer 200 and leave the failure to the error member; others map selected errors to HTTP statuses. A client must read the body either way, because the error object is where the specification puts the outcome.
  • On one stream where both ends send JSON-RPC 2.0 requests, how does a receiver tell an incoming Request from a Response?
    By its members: a Request has method, and an id unless it is a notification, while a Response has result or error and no method. Each side matches incoming Responses only against the requests it sent itself, so the two directions' ids do not collide even when both use 1, 2, 3.

saying these in an interview costs you the question

  • JSON-RPC 2.0 requires HTTP POST with status 200 for every response.
  • The specification defines newline-delimited framing for TCP streams.
  • A method-not-found error must be returned as HTTP 404.
  • JSON-RPC 2.0 lets only the side that opened the connection send requests.
  • JSON-RPC 2.0 defines a timeout after which a call is cancelled.