skip to content

In Selenium 4's WebDriver protocol, what does the value member of a command response body carry?

level: middleimportance: nice to knowfreq 32%

answer

  1. Every response has exactly one member
  2. The member is called value
  3. Null when there is nothing to return
  4. String, element object, array, or script result
  5. On failure it holds an error object

basics

~20 s

Every response is a JSON object with one member named value. On success it holds the command's result, which may be null, a string, an element object, an array or a script's return. On failure it holds an error object instead.

solid answer

~40 s

In Selenium 4 the remote end replies to every command with a single-member JSON object: `{"value": ...}`. What sits inside depends on the command - `null` for a click or a navigation, a string for the current URL or an element's text, an object holding an element handle for a find, an array for a bulk find, and whatever a script returned for `POST /session/{session id}/execute/sync`. When the command fails, `value` holds an error object with `error`, `message` and `stacktrace` instead of a result. The uniformity is why a client binding needs no per-command parser: it reads `value` and converts. The older Selenium 3 envelope, which carried `status` and `sessionId` beside `value`, no longer applies.

code

bash · 5 lines
bash
curl -s -X POST "http://localhost:4444/session/$SESSION/url" \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://fleet.internal/vehicles/overdue"}'

curl -s "http://localhost:4444/session/$SESSION/url"

go deeper

for a junior

Know that the driver replies to every command with JSON and that the useful part sits under a member called value. You are not expected to recite the shape per command.

for a middle

Be able to say what value holds for a click, a URL read, a find and a script call, and that a failure puts an error object there instead. This is the tier where the envelope is expected knowledge.

for a senior

Use it while diagnosing. Show that you can read a driver log or a captured body and tell a successful null result from a real failure without guessing.

for a principal

Frame it as why client bindings across languages stay consistent: one envelope means parity is cheap, and any custom tooling you build over the protocol inherits the same contract.

## One member, every time In Selenium 4 the remote end answers every command with a JSON object that has exactly one member, named **`value`**. Not a result field beside a status field, not a bare string, not an empty body: one object, one member. The command's outcome is whatever sits inside it. Selenium 3 spoke the older JSON Wire Protocol, whose body carried `status`, `sessionId` and `value` side by side; that envelope is gone in Selenium 4, and a candidate who describes it is describing history. The uniformity is the point. A client binding does not need a different parser per command; it reads `value` and hands the contents to whatever asked. In Java that is what `org.openqa.selenium.remote.Response#getValue()` returns, and every typed method on `WebDriver` and `WebElement` is a thin conversion over it. ## What value holds when the command succeeds The contents change shape with the command, and the shapes are worth knowing because they explain the return types you already use: - **`null`** for commands that produce nothing — an element click, a navigation, a window resize. The response body is `{"value": null}`, which is a successful response, not an empty one. - **A JSON string** for the plain text reads, such as the current URL, the page title or an element's rendered text. - **A JSON object** for a found element: a single-key object whose key is the standard web-element identifier and whose string is the handle the remote end will accept back in later paths. - **A JSON array** for a bulk find, holding zero or more of those same element objects. - **Whatever the script returned** for `POST /session/{session id}/execute/sync` — a number, a string, a boolean, an array, an object, or `null` — converted into JSON on the way out. - **A base64 string** for a screenshot command, which is why the Java binding can hand you bytes or a file from the same response. ## A worked pass over the fleet scheduler Consider a case that opens the depot's overdue list and reads the first work-order number: | Command | Route | What `value` carries | |---|---|---| | Navigate To | `POST /session/{id}/url` | `null` | | Get Current URL | `GET /session/{id}/url` | `"https://fleet.internal/vehicles/overdue"` | | Find Element | `POST /session/{id}/element` | one element object | | Get Element Text | `GET /session/{id}/element/{element id}/text` | `"WO-4417"` | | Element Click | `POST /session/{id}/element/{element id}/click` | `null` | Five commands, five bodies, one member each. The Java code that drives them reads as `driver.get(...)`, `driver.getCurrentUrl()`, `findElement(...)`, `getText()` and `click()`, and each of those calls is exactly one of these rows. ## When value carries a failure instead When the command fails, `value` is not the result — it is an **error object**. Its members are `error`, a fixed code string the specification defines; `message`, human-readable text from the remote end; `stacktrace`, the remote end's own trace; and optionally `data`, extra detail for the few errors that carry any. The client reads the code and raises the matching exception type, which is how a missing element on the fleet scheduler's overdue list becomes a `NoSuchElementException` in your test rather than a parse failure. So the envelope is genuinely uniform: the member is always `value`, and the only question is whether it holds a result or a failure description. ## Why this is worth knowing at all It is not trivia when something goes wrong. Three situations put you face to face with the raw body: 1. **Reading a driver log or a proxy capture** while diagnosing a failure — you need to recognise a successful `{"value": null}` and not read it as an empty or broken reply. 2. **Working against a remote end by hand**, with a command-line client, to prove whether the fault is in the browser stack or in the test code. 3. **Debugging a client binding or a custom command**, where you are the one unwrapping `value` yourself. - A successful click looks identical to a successful navigation on the wire; the route is what distinguishes them, not the body. - A `null` inside `value` is a normal outcome, never an error signal. - An empty array from a bulk find is a successful response whose `value` happens to be empty. - Nothing in the response tells the client what to do next — the local end decides that, because the contract only ever answers questions it was asked.

  • How does a client tell a successful command apart from a failed one if both bodies have the same member?
    By the response status of the reply, which the binding checks before unwrapping. When the command failed, the contents of `value` are an error object carrying `error`, `message` and `stacktrace`, and the client raises the exception type that matches the `error` code rather than returning the object to the caller.
  • Why does a find return an object rather than the element itself?
    Because the element never leaves the browser. The remote end keeps it and returns an opaque handle inside `value`; the client wraps that handle in a `WebElement`, and every later call on it becomes another request whose path carries the handle. Nothing about the element's state travels with the response.

saying these in an interview costs you the question

  • Says a successful click returns an empty response body
  • Expects a status field beside value, as Selenium 3 had
  • Reads a null value as an error rather than a result
  • Thinks the found element itself is serialised into the response
  • Assumes each command has its own response shape to parse