skip to content

In Appium, what must a client's server URL include when the server sets a base path?

level: middleimportance: should knowfreq 55%

answer

  1. the prefix sits in front of everything
  2. handshake lands at prefix plus session
  3. 404 means routing, not devices
  4. no driver has run yet

basics

~20 s

The base path itself, in front of every route. A server started with a base path answers the handshake at that prefix plus /session, so a client URL without the prefix gets HTTP 404 before any device work begins.

solid answer

~40 s

The `--base-path` / `-pa` flag prefixes the server's entire route table. So the client must be built on the host, port **and** that prefix: the handshake lands on the prefix plus `/session`, and every subsequent command on the prefix plus `/session/:sessionId/...`. Omit it and the server answers `404` — it is listening, the connection succeeds, but nothing is registered at the path you asked for. That failure is diagnostic: a `404` on the handshake is always a routing mistake, never a device or capability mistake, because no driver has run yet. The mirror mistake is adding a prefix the server was not started with, which produces the same `404` from the other direction.

code

bash · 11 lines
bash
# Server started with: appium --base-path /wd/hub --port 4723

# Wrong: 404, because no route is mounted at the root
curl -s -o /dev/null -w '%{http_code}\n' -X POST http://appium-host:4723/session \
  -H 'Content-Type: application/json' \
  -d '{"capabilities":{"alwaysMatch":{"platformName":"Android","appium:automationName":"UiAutomator2"}}}'

# Right: the base path prefixes every route, handshake included
curl -s -o /dev/null -w '%{http_code}\n' -X POST http://appium-host:4723/wd/hub/session \
  -H 'Content-Type: application/json' \
  -d '{"capabilities":{"alwaysMatch":{"platformName":"Android","appium:automationName":"UiAutomator2"}}}'

go deeper

for a junior

Be ready to state that a base path prefixes the whole route table, so the client URL needs host, port and prefix together before any session can start.

for a middle

Explain the failure signature: a 404 on the handshake proves the server answered and routed nowhere, so no driver ran and no capability was validated.

for a senior

Show the triage order you use on an unfamiliar endpoint — connection error, then status code, then driver message — and why editing capabilities on a 404 wastes a cycle.

for a principal

Argue for treating the whole base URL as one per-environment string rather than assembling it from parts, and explain which class of onboarding failure that removes.

## What a base path actually does An Appium server exposes a route table — `POST /session`, `DELETE /session/:sessionId`, `POST /session/:sessionId/actions`, and so on. The `--base-path` / `-pa` flag mounts that entire table underneath a prefix. It is not a special case for the handshake and it is not a redirect; it is a prefix applied uniformly, so every route the server knows about moves together. A client therefore has to be built on host, port **and** prefix, and once it is, everything else behaves exactly as before. Concretely, with a prefix of `/wd/hub`: - the handshake is `POST /wd/hub/session`; - a command inside the session is `/wd/hub/session/:sessionId/...`; - teardown is `DELETE /wd/hub/session/:sessionId`. ## Why this bites specifically on a remote endpoint On your own machine you usually start the server yourself, so you know whether a prefix is set. A server someone else started is opaque: the address tells you nothing about how it was launched. The prefix is the single most common reason a capability set that works against one endpoint fails against another without a line of it changing. It is also the mistake that produces the most confusing failure report, because the symptom arrives from the HTTP layer while the person reading it is thinking about devices. Nothing in the message mentions Android, iOS, a driver or a device — and that absence is exactly the clue. ## Reading the failure | Symptom | What it means | Where the fault is | |---|---|---| | Connection refused | Nothing is listening at that host and port | Host, port, or a listener bound to loopback | | HTTP 404 on the handshake | Something answered; no route at that path | Base path, or a scheme reaching a different service | | A driver error naming a device | The server routed and a driver ran | The capability set or the device, not the URL | The middle row is the one this subject owns. A `404` from `POST /session` means the server process is alive and reachable and simply has no route where you knocked. No device has been touched, no driver has been selected, and no capability has been validated — so re-reading your Android or iOS capabilities is wasted effort. ## The two directions of the same mistake 1. **Prefix missing from the client.** The server was started with a base path; the client was built on host and port alone. Every request 404s, starting with the handshake. 2. **Prefix present in the client but not on the server.** A suite carries a historical prefix in its configuration and is pointed at a server that mounts its routes at the root. Same `404`, opposite cause. Both are configuration mismatches between two independently launched processes, and neither is visible from either side alone. That is why the check below is worth running by hand once per new endpoint. ## Checking it without a test run - Send the handshake yourself, from the machine that will run the suite, and look only at the status code. You do not need it to succeed; you need it to *not* be a `404`. - Try the URL with and without the prefix. Exactly one of the two should stop 404ing. - Confirm the scheme as well. A client speaking `http` to a server started with `--ssl-cert-path` and `--ssl-key-path` fails at the transport, which looks different again from a `404`. - Once a request reaches a driver, stop looking at the URL. From that point the message will name a platform, a device or a capability, and the endpoint has done its job. ## What does not change with the prefix Nothing in the payload. The prefix is part of the address, so an Android capability set (`platformName` of `Android`, `appium:automationName`, Android's `appium:appPackage`) and an iOS one (`platformName` of `iOS`, iOS's `appium:bundleId`) are byte-for-byte the same whether or not a prefix is in play. This is worth stating explicitly in a review, because the instinct on a `404` is to start editing capabilities, and that instinct is always wrong here: capabilities are not addressed by the route table and cannot cause a routing miss. ## Keeping it out of your test code The practical habit is to treat the whole base URL — scheme, host, port and prefix together — as one opaque string supplied per environment, rather than assembling it from parts scattered through a configuration file. Assembled URLs are where a prefix quietly gets dropped as a new environment is added, and a single string makes the difference between two endpoints inspectable at a glance. It also makes the base path visible to whoever reads the configuration next, which is the only durable defence against rediscovering this failure once per person.

  • How do you tell a base-path mismatch from an unreachable host without reading any logs?
    By the failure kind. An unreachable host or wrong port gives a connection-level error — nothing answered. A base-path mismatch gives an HTTP 404 — something answered and routed you nowhere. The first is about reachability, the second about routing, and neither has reached a driver.
  • Does the base path change anything about commands after the handshake?
    It prefixes them too. Session-scoped routes become the prefix plus /session/:sessionId/... and teardown becomes DELETE on that same prefixed path. Clients build these from the base URL you gave them, so getting the base URL right once fixes the whole session.

saying these in an interview costs you the question

  • Thinks the base path applies only to the handshake
  • Edits capabilities in response to an HTTP 404
  • Assumes any server answers at the root path
  • Confuses the base path with the listening port
  • Reports a routing 404 as a device unavailability