## TL;DR

ERR_NAME_NOT_RESOLVED is the browser failing DNS, not your app failing. The test browser resolves names differently than your dev machine: CI containers, Docker networks, and proxy env vars all change DNS. Find where the name should resolve (hosts file, stub, or real DNS), make it resolvable from the test environment, and stub the endpoint if it should never hit the network.

## Error

```text
playwright requestfailed on xhr with ERR_NAME_NOT_RESOLVED: how to fix
```

API calls fail with requestfailed and ERR_NAME_NOT_RESOLVED while the page itself loads fine.

## Steps

1. Confirm it is DNS: the failed request shows requestfailed with ERR_NAME_NOT_RESOLVED, not a status code. Expected output: you have ruled out app-level errors.
2. Check whether the hostname should hit the network at all; if it is a test double, replace it with page.route and route.fulfill. Expected output: the request never leaves the browser.
3. If it must hit the network, resolve the name from the test environment's shell (the CI container, not your laptop). Expected output: you see the same failure or success the browser sees.
4. Fix the environment: add a hosts entry, fix the Docker network's DNS, or set the proxy vars the headless browser needs. Expected output: the hostname resolves from the test shell.
5. Re-run the test and watch the request succeed. Expected output: no more requestfailed events for that host.

## When to use

- XHR calls fail with ERR_NAME_NOT_RESOLVED while the page loads.
- API tests pass locally but fail in Docker or CI.
- You need to decide between stubbing and fixing DNS.

## When not to use

- Requests fail with 4xx or 5xx (the server responded; DNS is fine).
- Failures mention CORS or certificate errors (different browser security layer).
- The hostname is intentionally unreachable (that is the test; assert the failure).

## Variant phrasings

### Works headed, fails headless

Headless shells often lack the proxy env vars the headed shell has; export them in the CI job before launching.

### DNS failure only in Docker

Docker's embedded DNS does not read the host's resolver config; add explicit DNS or extra hosts to the container.

### requestfailed versus bad status

requestfailed means the request never got an answer; a 500 means it did. Diagnose at the right layer.

## Why it happens

Playwright launches a real browser with the environment's real resolver. Developers test against hostnames that resolve via local DNS tricks (corporate resolvers, hosts files, VPN) which do not exist inside CI containers, so the browser cannot even start the request.

## Edge cases

- page.route handlers that forget to call route.continue or route.fulfill hang the request and look like network failures.
- Service workers can cache a DNS failure and replay it; clear storage or unregister the worker when debugging.
- IPv6-first resolvers can return AAAA records the test network cannot route; forcing IPv4 in the container is a legitimate workaround.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_RC5FUqw4Gl6X9RD93jT7Fg
