skip to content

In Selenoid, what does browsers.json decide, and what does a client get if its browser is missing?

level: middleimportance: should knowfreq 55%

answer

  1. the server decides what exists
  2. name, then default, then versions
  3. prefix matching, with the request on the short side
  4. an unlisted browser is an argument error
  5. capacity and catalogue fail differently

basics

~20 s

Selenoid's browsers.json is the catalogue of what the server will start: browser name, default version, and per version the image, port and path. An unlisted browser draws invalid argument, though a busy server queues it before refusing.

solid answer

~50 s

In Selenoid — unmaintained by its own README, as all four Aerokube repositories are — `browsers.json` maps a browser name to a `default` version and a `versions` object, and each version entry names the container `image`, the `port` the driver listens on and the `path` it serves WebDriver at, plus optional `tmpfs`, `env`, `volumes`, `hosts`, `shmSize`, `mem` and `cpu`. Matching is deliberately loose: with no version requested Selenoid uses that browser's `default`, and otherwise it takes a catalogue key that **starts with** the requested string — an arbitrary one when several do, since the keys are ranged as a map. If nothing matches, Selenoid logs `[ENVIRONMENT_NOT_AVAILABLE]` and answers with the W3C error `invalid argument` carrying "Requested environment is not available". Catalogue and capacity differ: an idle grid still refuses a browser it does not list, and adding one means editing the file and having the image on the host.

code

json · 12 lines
json
{
  "chrome": {
    "default": "latest",
    "versions": {
      "latest": {
        "image": "selenoid/chrome",
        "port": "4444",
        "tmpfs": {"/tmp": "size=512m"}
      }
    }
  }
}

go deeper

for a junior

Know that Selenoid will only start browsers listed in browsers.json, and that each entry names the image to run. Being able to read the file and say which browsers this grid serves is enough at this level.

for a middle

Be ready to walk the resolution path: browser name, then default version when none is asked for, then prefix matching against the version keys, with the request on the short side. Say what the client gets when nothing matches, and why that is an argument error rather than a capacity error.

for a senior

Expect a diagnosis scenario. Separate an argument error about an unavailable environment from a session-not-created failure, and know that catalogue drift between hosts in a cluster looks like flakiness from the suite's side.

for a principal

Think about who owns the catalogue. Decide whether browser versions are pinned per suite or per grid, how a new version is rolled out across hosts without a window where some serve it and some do not, and who is allowed to edit the file.

`browsers.json` is Selenoid's catalogue. It is the only place the server learns that a browser exists, which container image represents it, and how to talk to the driver inside that image. Selenoid is unmaintained by its own README, so treat the file as a very legible example of a pattern — a hosted provider maintains the same catalogue for you and simply never shows it to you. ## What the file holds The outer object is keyed by browser name, matched against the `browserName` capability as a plain string. Each browser carries: - `default` — the version used when the request names none. - `versions` — an object whose keys are version labels and whose values are the browser entries. Each version entry can carry: - `image` — the container image to start, or a driver binary command when Selenoid runs without Docker. - `port` — the port inside the container that the driver listens on. - `path` — the path where a new session is requested, which differs between browser images. - `tmpfs`, `volumes`, `env`, `hosts`, `shmSize`, `mem`, `cpu` — optional per-browser container settings. `volumes` is the hole in the isolation story: Selenoid's documentation describes it as mounting a host path into the browser, so what is written there is not in the container to destroy. A custom location for the file is passed with Selenoid's `-conf` flag. ## How a request is resolved 1. Look the `browserName` up as an exact string key. Not present means no match at all. 2. If the request carries no version, substitute that browser's `default`. If `default` is empty too, there is no match. 3. Otherwise scan the `versions` keys and take one whose label **begins with** the requested string. Selenoid ranges those keys as a map, so when more than one label matches, which one you get is arbitrary and need not repeat on the next identical request. 4. On a match, start a container from that entry's `image` and proxy to its `port` and `path`. ## What the client sees when there is no match Selenoid writes `[ENVIRONMENT_NOT_AVAILABLE]` to its log with the requested name and version, and answers the client with the W3C error name `invalid argument` and the message "Requested environment is not available". It is a *different* failure from the one people expect: | Situation | What Selenoid answers | |---|---| | Browser or version not in the catalogue | `invalid argument`, "Requested environment is not available" | | Catalogue entry exists but the container will not start | `session not created` | | A `sessionTimeout` value it cannot parse | `invalid argument`, "invalid sessionTimeout capability" | So an operator reading `invalid argument` should reach for the catalogue and the capabilities, while `session not created` points at the host: a missing image, an exhausted disk, a daemon that will not cooperate. ## Catalogue is not capacity This is the part that catches people out on a self-operated grid. The catalogue answers *what may be started*; the run limit answers *how much may run at once*. They fail differently and they are fixed differently. - A grid sitting completely idle will still refuse a browser it does not list, immediately and permanently, until somebody edits the file. - Adding a browser is two actions, not one: an entry in `browsers.json` **and** the image present or pullable on that host. - In a cluster every host has its own copy of the file, so a browser can be available through one host and absent through another — a real source of a suite that passes on most attempts. - The prefix rule runs one way only: a coarse **request** is absorbed by a fuller catalogue label, never a coarse label by a specific request. Asking for a major version lands on whatever build the catalogue files under it; asking for a build more specific than the label matches nothing, and draws the same argument error as an unlisted browser. - The gate is taken before the lookup, so on a server at its run limit even a catalogue miss waits for a slot before it is told no. Refusing instead of waiting is opt-in, through Selenoid's `-disable-queue` flag or its `X-Selenoid-No-Wait` header. ## Operating the file for a real suite For a hospital rota planner's suite the practical checklist is short: - Pin the labels your suite actually asks for, and make the client's capability and the catalogue key agree deliberately rather than by luck. - Keep the image reference explicit, and pull it onto the host before the first run rather than discovering the pull inside a session's start-up. - Use the per-entry container settings where the browser needs them — shared memory and scratch space are the usual culprits behind a browser that dies under load. - Treat the file as configuration under version control, and diff it between hosts. ## What an interviewer is listening for - That the catalogue is server-side, so a client cannot conjure a browser by asking harder. - That version matching is by prefix and that an absent version falls back to `default`. - That an unlisted browser produces an argument error rather than a capacity failure, while being honest that a full server makes it wait for a slot before saying so. - That adding a browser means both a file edit and an image on the host.

  • Your rota planner suite asks for a browser that one grid host serves and another does not. How does that show up?
    As an intermittent `invalid argument` with "Requested environment is not available", correlated with which host answered rather than with the test. Each Selenoid keeps its own `browsers.json`, so a catalogue that has drifted between hosts produces exactly this. Diff the files across the hosts and compare the images actually present on each.
  • Why does the version entry need a path as well as a port?
    Because the browser images do not all serve WebDriver at the same place. Selenoid's own documentation notes that Chrome and Opera images use `/` while the Firefox image uses `/wd/hub`. The `port` says where the driver listens inside the container and the `path` says where to request a new session, and getting either wrong shows up as a session that never starts.

saying these in an interview costs you the question

  • Thinks a client capability can request a browser the server does not list
  • Expects an unlisted browser to start once capacity frees up
  • Believes catalogue version keys are matched by exact equality
  • Adds a browsers.json entry without making the image available
  • Assumes every host in a cluster shares one catalogue file