QA How-To
How to Fix Playwright net::ERR_NAME_NOT_RESOLVED
Fix Playwright net::ERR_NAME_NOT_RESOLVED by tracing the failed URL, checking DNS in CI or Docker, and correcting baseURL, redirects, proxies, or asset hosts.
22 min read | 3,546 words
TL;DR
Identify the failed request URL, resolve its hostname from the browser environment, and correct the owning URL or network configuration. Check baseURL, redirects, Docker service names, CI variables, and proxy rules before changing timeouts.
Key Takeaways
- Capture the exact failed URL before changing timeouts or DNS settings.
- Resolve and probe the hostname from the environment where the browser runs.
- Align baseURL and webServer targets for local tests, then check absolute URLs separately.
- Inspect redirects and subresource failures when the initial page is reachable.
- Use Compose service names inside its network and validate CI target variables early.
- Verify the repair through DNS, HTTP, and browser navigation checks.
If you need to fix Playwright net::ERR_NAME_NOT_RESOLVED, the error appears when a browser navigation or page resource names a host that the browser cannot resolve to an address. Find the exact failed URL first, then test its hostname from the same machine or container that runs the browser.
page.goto: net::ERR_NAME_NOT_RESOLVED at https://app.example.invalid/
The hostname above is illustrative; your stack trace contains the useful one. A page.goto failure identifies the main document. A requestfailed event may instead identify an image, script, API call, or redirect destination. These cases need different fixes even though Chromium shows the same network code. Playwright's navigation API throws when the main resource cannot load, while a valid HTTP 404 or 500 returns a response that you must inspect.
TL;DR
Copy the URL that actually failed. Check its parsed hostname, resolve it in the runner environment, and probe the address over HTTP. For a local app, make use.baseURL, webServer.url, and the app's listening host agree. For Docker Compose, use the app service name inside the test container. For CI, pass the intended environment URL explicitly and fail early if it is missing.
node --input-type=module -e "const u = new URL(process.env.APP_URL || 'http://127.0.0.1:4173/'); console.log({ href: u.href, hostname: u.hostname })"
Set APP_URL to your real target before running the probe. If DNS resolves but the port rejects the connection, use the Playwright connection refused guide. If webServer never becomes ready before specs run, use the webServer configuration guide. Do not increase a navigation timeout to solve a hostname that will never resolve.
What the Error Actually Means
A URL supplies a hostname, such as app.internal, that must be translated into an IP address before a connection can start. net::ERR_NAME_NOT_RESOLVED is Chromium's report that this name resolution failed. It does not prove the target application crashed, the port is closed, or the TLS certificate is invalid. Those are later stages of a request. Firefox and WebKit can express equivalent failures with different wording, so diagnose the failed URL rather than matching only one browser's text.
The browser may run somewhere other than your terminal: a CI runner, a Docker container, or a remote Playwright server. Name resolution has to work where that browser runs. A successful curl on your laptop does not establish that a container can resolve the same private hostname. Conversely, Node's DNS lookup is a useful first check but does not reproduce every browser proxy or resolver behavior. Compare both a system probe and an actual browser navigation when the results differ.
Playwright's use.baseURL resolves relative URLs passed to page.goto('/'); it does not rewrite a fully qualified URL hardcoded in a spec. webServer.url only checks whether an app started. If readiness uses 127.0.0.1 but baseURL points to frontend, the runner can start successfully and the browser can still fail at navigation. The official web server documentation describes the two settings separately.
First determine whether the failed request is the top-level document, a redirect target, or a subresource. A resource failure can leave the page visible while an assertion fails later. The network traffic guide expands on request and response events when you need more detail.
Root-Cause Decision Table
| Symptom | Root cause | Fix |
|---|---|---|
page.goto('/') expands to an unexpected host |
Wrong baseURL or missing environment value |
Print the resolved URL and set one validated origin |
| Failed URL contains a typo or obsolete domain | Hostname in test data is wrong | Correct the source of that URL; resolve the corrected name |
| Initial page is reachable but navigation fails after a redirect | Redirect points to a host unavailable in this environment | Fix the server's canonical URL or authentication callback |
| Works on the host but fails inside Docker | Service name or network scope mismatch | Use the Compose service name and shared network |
| Works locally but fails in CI | CI secret, environment URL, or private DNS is absent | Inject and verify the URL in the job's network |
| Only fails behind a corporate network | Proxy or VPN routes DNS differently | Configure the supported proxy or run in a permitted network |
| Main page loads but one asset or API request fails | Secondary hostname cannot resolve | Repair asset/API origin or mock only that dependency |
| DNS lookup succeeds but browser still fails | Browser proxy, DNS cache, or different browser location | Check browser context and actual failed request |
Use the table as a route to evidence, not as a list of settings to change at once. The next sections give a code path and a verification command for each cause. Preserve the full failing URL in logs, but redact tokens in query strings before sharing them.
1. Fix Playwright net::ERR_NAME_NOT_RESOLVED Caused by a Wrong baseURL
A relative navigation inherits the origin in use.baseURL. If a CI variable is empty, mistyped, or points at a domain available only on a developer laptop, the spec may report a DNS error even though the app is healthy at another address. Make the origin explicit and log the URL before navigation. This also separates a bad test target from an application failure.
Here is a minimal, self-contained local fixture. Save server.mjs in a scratch Playwright project. It uses Node's built-in HTTP server and needs no framework-specific route. Keep this server running in one terminal for the next probe; later Playwright can own its lifecycle.
// server.mjs
import { createServer } from 'node:http';
createServer((request, response) => {
response.writeHead(200, { 'content-type': 'text/html' });
response.end('<!doctype html><title>Ready</title><h1>Ready</h1>');
}).listen(4173, '127.0.0.1', () => {
console.log('Listening on http://127.0.0.1:4173');
});
node server.mjs
In a second terminal, verify the fixture and the exact origin you intend to test. curl must print an HTTP response; a successful DNS lookup alone is insufficient to prove the app is listening.
curl -i --max-time 5 http://127.0.0.1:4173/
Now save playwright.config.ts. The environment override is optional for local work, but a CI job must supply a valid APP_URL. new URL() rejects malformed values immediately. Avoid silently constructing an origin from unrelated host and port variables.
// playwright.config.ts
import { defineConfig } from '@playwright/test';
const appURL = new URL(process.env.APP_URL ?? 'http://127.0.0.1:4173');
console.log(`Testing origin: ${appURL.origin}`);
export default defineConfig({
use: { baseURL: appURL.origin },
});
Save this smoke spec as tests/name-resolution.spec.ts. It asserts an actual response and visible page content, so a reachable server returning a bad status cannot pass by accident.
// tests/name-resolution.spec.ts
import { test, expect } from '@playwright/test';
test('home page resolves and responds', async ({ page, baseURL }) => {
if (!baseURL) throw new Error('baseURL is required');
console.log(`Navigating to ${new URL('/', baseURL).href}`);
const response = await page.goto('/');
expect(response).not.toBeNull();
expect(response?.ok()).toBe(true);
await expect(page.getByRole('heading', { name: 'Ready' })).toBeVisible();
});
Verify with npx playwright test tests/name-resolution.spec.ts. The fixture must still run in the first terminal. If your real app uses a different route, replace the heading assertion with a stable marker from that app. This Playwright debugging guide helps when the browser reaches the page but a later assertion fails.
2. Fix Playwright net::ERR_NAME_NOT_RESOLVED When the Hostname Is Misspelled
A single extra character in a staging domain is enough to produce the error. Sometimes the typo is in APP_URL; sometimes it sits in a page object, fixture, redirect allowlist, or test data. Read the hostname from the failed URL rather than guessing from the test title. A URL like http://localhsot:4173/ is syntactically valid, so new URL() will not catch the spelling error.
Use this portable Node probe with the actual URL. It prints the parsed host and asks the system resolver for an address. It does not require dig or getent, which may be absent from lightweight CI images.
APP_URL=http://localhsot:4173/ node --input-type=module -e "import { lookup } from 'node:dns/promises'; const u = new URL(process.env.APP_URL); console.log('host:', u.hostname); try { console.log(await lookup(u.hostname)); } catch (error) { console.error(error.code, error.message); process.exitCode = 1; }"
The deliberately misspelled localhsot should fail resolution on a normal machine. Repeat with the real, corrected host. For local development, http://127.0.0.1:4173/ avoids any hostname spelling question; for a shared environment, obtain the canonical hostname from deployment output or environment configuration. Do not replace an unknown production host with 127.0.0.1: that points to the browser's own machine.
Search the repository for the exact failed hostname, including the spelling found in the trace:
rg -n 'localhsot|APP_URL|baseURL' playwright.config.ts tests .github
If rg is unavailable, use your editor's search. Change the owner of the value, then verify with the DNS probe and npx playwright test tests/name-resolution.spec.ts. A typo can also occur in a fully qualified page.goto('https://...') call; such a call ignores baseURL, so changing config alone will not repair it. Keep absolute URLs only where the test intentionally crosses origins.
3. Repair a Redirect to a Name the Browser Cannot Resolve
The initial hostname may resolve correctly while the server returns a Location header to a different host. Authentication gateways, canonical-domain middleware, and reverse proxies commonly produce this pattern. Playwright follows redirects during page.goto, and the final failed hostname may appear only after the first response. Inspect the redirect chain before editing DNS or increasing timeouts.
Run this probe against your application, replacing the example origin. -L follows redirects, while the header-only command shows the first response and its Location. Do not paste a sensitive callback URL or token into shared logs.
curl -i --max-time 10 http://127.0.0.1:4173/
curl -IL --max-time 10 http://127.0.0.1:4173/
If the first response says Location: https://old-staging.example.invalid/login, locate the app setting that constructs the canonical URL or identity-provider callback. Set it to a hostname resolvable in the test environment. For example, this complete Node redirect fixture takes its public origin from an environment variable instead of embedding an obsolete domain. Save it as redirect-server.mjs and start it in place of server.mjs when testing a redirect:
// redirect-server.mjs
import { createServer } from 'node:http';
const publicOrigin = new URL(process.env.PUBLIC_ORIGIN ?? 'http://127.0.0.1:4173');
createServer((request, response) => {
if (request.url === '/') {
response.writeHead(302, { location: new URL('/login', publicOrigin).href });
response.end();
return;
}
response.writeHead(200, { 'content-type': 'text/html' });
response.end('<!doctype html><h1>Login</h1>');
}).listen(4173, '127.0.0.1');
Verify with PUBLIC_ORIGIN=http://127.0.0.1:4173 node redirect-server.mjs in one terminal and curl -IL http://127.0.0.1:4173/ in another. The final URL should be /login on the same origin. Stop the earlier fixture first to free port 4173. In your real app, set its equivalent public-origin or callback configuration rather than copying this fixture into production. Avoid a Playwright route that merely hides the redirect unless the redirect itself is intentionally outside the test's scope.
Capture the browser's sequence as a second check. Save the following as tests/redirect-diagnostic.spec.ts; set APP_URL to a real address before running it. A request failure event supplies the exact URL and browser failure text.
// tests/redirect-diagnostic.spec.ts
import { test } from '@playwright/test';
test('log navigation and failed requests', async ({ page }) => {
const target = process.env.APP_URL;
if (!target) throw new Error('Set APP_URL to the failing page URL');
page.on('request', request => console.log('REQUEST', request.url()));
page.on('response', response => console.log('RESPONSE', response.status(), response.url()));
page.on('requestfailed', request =>
console.log('FAILED', request.url(), request.failure()?.errorText)
);
await page.goto(target);
});
Verify with APP_URL=http://127.0.0.1:4173/ npx playwright test tests/redirect-diagnostic.spec.ts. The simple fixture has no redirect, so it passes. Run it against the affected environment to expose a redirect destination. If the browser stops before a final response, compare the last REQUEST and FAILED lines with the curl headers.
4. Correct Docker Hostnames and Network Scope
Inside a Playwright container, localhost means that container, and a Compose service name resolves only for containers attached to the same Compose network. A name such as web will usually not resolve from your laptop. Decide whether the app is another container or runs on the host, then choose the address from the browser's point of view. An unresolved Compose name often produces ERR_NAME_NOT_RESOLVED; pointing at localhost more often produces ERR_CONNECTION_REFUSED when no server listens there.
For an app and tests in one Compose project, use the app's service name and internal port. Here is a focused compose.yaml shape for an npm app whose npm run dev accepts Vite-style host and port arguments:
services:
web:
build: .
command: npm run dev -- --host 0.0.0.0 --port 4173 --strictPort
expose:
- "4173"
tests:
image: mcr.microsoft.com/playwright:v<your-playwright-version>-noble
working_dir: /work
volumes:
- .:/work
environment:
APP_URL: http://web:4173
depends_on:
- web
command: sh -c "npm ci && npx playwright test tests/name-resolution.spec.ts"
Replace the image placeholder with the installed @playwright/test version and make sure your Dockerfile builds the app. The placeholder is intentional; do not copy it verbatim. A bind to 0.0.0.0 lets the app accept connections from the tests container. depends_on orders startup but does not establish HTTP readiness, so use Playwright's webServer readiness option or a health check when cold startup matters. See Playwright's Docker guidance for container and version matching details.
Verify the address from the test service, not from the host:
docker compose run --rm tests node --input-type=module -e "import { lookup } from 'node:dns/promises'; console.log(await lookup('web'))"
docker compose run --rm tests node --input-type=module -e "const r = await fetch('http://web:4173/'); console.log(r.status); if (!r.ok) process.exitCode = 1"
For an application running on the Docker host instead, Playwright documents adding a host-gateway alias such as hostmachine and then navigating to that alias. The host application must accept traffic from the container. Keep this as a separate topology from Compose service discovery; mixing their hostnames makes a healthy app look unreachable.
5. Supply a Reachable URL in CI
CI often runs without your shell's APP_URL, VPN, or private DNS zone. A local .env file may never reach the job. If the config silently falls back to a development hostname, the test can attempt to resolve the wrong place. Validate the variable at the job boundary and print the hostname, never credentials or complete URLs containing tokens.
For a GitHub Actions job that tests an already deployed environment, the following step fails early when the variable is absent. Configure APP_URL as a repository variable or job environment value, then put the check before the Playwright command. The example assumes dependencies and browsers have already been installed by earlier steps.
- name: Check target hostname
env:
APP_URL: ${{ vars.APP_URL }}
run: |
node --input-type=module -e "import { lookup } from 'node:dns/promises'; const raw = process.env.APP_URL; if (!raw) throw new Error('APP_URL is missing'); const url = new URL(raw); console.log('Target host:', url.hostname); console.log(await lookup(url.hostname));"
node --input-type=module -e "const response = await fetch(process.env.APP_URL); console.log('HTTP status:', response.status); if (!response.ok) process.exitCode = 1"
- name: Run Playwright
env:
APP_URL: ${{ vars.APP_URL }}
run: npx playwright test tests/name-resolution.spec.ts
The DNS command distinguishes an absent or unresolvable target from a server that returns an unhealthy HTTP status. A private staging URL may require a self-hosted runner connected to the private network or a supported tunnel. Setting the URL alone cannot grant that network access. If your CI starts the app locally, use webServer and a local baseURL instead of a remote staging address; the Playwright GitHub Actions guide covers a fuller pipeline.
Verify in the CI log that the printed hostname matches the intended deployment, then check the HTTP status and the smoke test. If DNS works in a shell step but fails only in a remote browser service, repeat the probe where that browser service runs. Rerunning the job without checking the target host can make a transient DNS incident look like a test flake.
6. Configure a Required Proxy or VPN Deliberately
A corporate staging domain may resolve only through a company network. A laptop connected to a VPN can pass while a cloud runner cannot. Some environments also require an HTTP or SOCKS proxy for outbound browser traffic. Playwright supports a proxy setting under use, including server and bypass; the official network guide documents the option. Use a proxy address supplied by your organization, not a made-up public proxy.
This config activates the proxy only when PLAYWRIGHT_PROXY is supplied. It keeps the direct path for local app tests and fails visibly if the configured URL itself is malformed.
// playwright.config.ts for a proxied environment
import { defineConfig } from '@playwright/test';
const raw = process.env.APP_URL;
if (!raw) throw new Error('APP_URL is required');
const target = new URL(raw);
const proxyServer = process.env.PLAYWRIGHT_PROXY;
export default defineConfig({
use: {
baseURL: target.origin,
...(proxyServer ? { proxy: { server: proxyServer } } : {}),
},
});
Verify in the network that actually runs the browser:
APP_URL=https://your-real-staging-host.example/ npx playwright test tests/redirect-diagnostic.spec.ts
Replace the placeholder address with your real staging URL; it is not expected to resolve as written. If policy requires a proxy, set PLAYWRIGHT_PROXY to the approved server and rerun the same test. A successful curl can use shell proxy variables that Chromium does not use in the same way, so browser success is the deciding check. A VPN's split DNS may require the runner to join that network; a browser proxy cannot fix a private name if the proxy itself cannot reach it.
7. Fix an Asset or API Host That Fails After the Main Page Loads
Sometimes page.goto('/') succeeds and the app still breaks because JavaScript requests api.old-domain.invalid or a stylesheet comes from a removed CDN. A top-level response.ok() assertion will not detect every failed subresource. Log requestfailed, inspect the request's resource type, and repair the origin in the application configuration or deployed asset manifest.
Save this diagnostic spec with an app URL that serves a real page. It collects failed URLs while the page settles on a visible marker. Change the marker to one from your application. The code uses Playwright's real request event API and fails with a compact list rather than hiding the browser error.
// tests/subresource-diagnostic.spec.ts
import { test, expect } from '@playwright/test';
test('page loads without DNS failures', async ({ page }) => {
const failures: string[] = [];
page.on('requestfailed', request => {
const reason = request.failure()?.errorText ?? 'unknown failure';
if (reason.includes('ERR_NAME_NOT_RESOLVED')) {
failures.push(`${request.resourceType()} ${request.url()}`);
}
});
await page.goto('/');
await expect(page.locator('body')).toBeVisible();
expect(failures, failures.join('\n')).toEqual([]);
});
Verify against the local fixture with npx playwright test tests/subresource-diagnostic.spec.ts; it should pass because the fixture loads no external resources. Then run the same spec against the affected app by setting APP_URL in the first config. If the app loads resources after user interaction, perform that interaction before the final assertion. If requests are intentionally blocked, classify those failures separately rather than asserting that every request succeeds.
When the external dependency is irrelevant to the behavior under test, intercept only its precise URL and fulfill it with a controlled response. For example, add this before page.goto('/') in the diagnostic test when an intentionally external JSON endpoint is unavailable:
await page.route('https://api.example.invalid/catalog', route =>
route.fulfill({ status: 200, contentType: 'application/json', body: '{"items":[]}' })
);
Replace the illustrative endpoint with the exact request your app makes, then verify with npx playwright test tests/subresource-diagnostic.spec.ts. Keep the route only if the test deliberately excludes that dependency; Playwright route fulfillment can supply a stable fixture. A broad **/* mock would conceal broken application URLs and can prevent the main document from loading. The network mocking interview guide discusses that trade-off in test design.
How to Verify the Fix
Use the same browser location and target URL that originally failed. First resolve the exact hostname, then make an HTTP request, then run a focused Playwright navigation. These are three different checks: DNS, transport/application response, and browser behavior. Passing an earlier check does not prove the later one.
APP_URL=http://127.0.0.1:4173/ node --input-type=module -e "import { lookup } from 'node:dns/promises'; const u = new URL(process.env.APP_URL); console.log(u.hostname, await lookup(u.hostname));"
curl -i --max-time 5 http://127.0.0.1:4173/
APP_URL=http://127.0.0.1:4173/ npx playwright test tests/name-resolution.spec.ts
For the local fixture, keep node server.mjs running while those commands execute. Expect an address from the Node lookup, an HTTP 200 from curl, and one passing test. For the real target, substitute its exact URL in every command; a different curl target proves little. If the failure originally occurred after a click or login, run the workflow through that point and inspect the redirect or subresource event as well.
Check each configured browser project if your suite uses Chromium, Firefox, and WebKit. The exact error string may vary, but the target should load in each supported project. Playwright traces can preserve navigation and request details for a failing retry; the trace-on-retry guide explains the setup. Once the focused check passes in the affected runner, run the normal suite so dependent routes and assets get exercised.
Prevent It From Coming Back
Keep one documented source for each environment's app origin. Validate APP_URL before starting browser work and print only its hostname in CI logs. Avoid silent fallbacks to private staging domains in jobs that do not have private DNS. Put the target origin alongside the deployment job that creates it, so a domain rename updates both deployment and tests.
For local apps, let Playwright's webServer start the server and use a matching baseURL. A concise configuration for the Node fixture above is:
// playwright.config.ts for server.mjs
import { defineConfig } from '@playwright/test';
const origin = 'http://127.0.0.1:4173';
export default defineConfig({
webServer: {
command: 'node server.mjs',
url: `${origin}/`,
reuseExistingServer: !process.env.CI,
},
use: { baseURL: origin },
});
Stop any manually started fixture before running this config in CI mode. Verify with CI=1 npx playwright test tests/name-resolution.spec.ts; Playwright should start and stop the fixture itself. If this command instead reports an existing listener, identify that process before rerunning. Keep Docker service names scoped to their network, and keep image versions aligned with the installed Playwright package. Review redirect destinations when identity-provider or canonical-domain settings change.
Add a small smoke test to the pipeline that loads the real entry point and records failed request URLs. That check gives a quicker signal than waiting for every feature test to fail. Avoid adding blind retries around DNS failures: retries are useful for confirmed transient infrastructure incidents, but they can conceal a permanently wrong host.
Interview Questions and Answers
Q: What layer fails when Chromium reports net::ERR_NAME_NOT_RESOLVED?
Hostname resolution failed before a TCP connection could be made. I capture the exact request URL and check resolution where the browser runs. I do not infer a server crash from this message alone.
Q: Why can webServer.url pass while page.goto('/') fails?
The readiness probe and navigation may use different origins. webServer.url gates startup, while use.baseURL resolves relative page URLs. I print both effective URLs and align them with the runner's network.
Q: How do you identify a redirect-driven DNS failure?
I inspect the initial response's Location header with curl -i and log browser request and response events. The final failed hostname may belong to an authentication or canonical-domain redirect rather than the page initially requested.
Q: What changes when Playwright runs in Docker Compose?
The browser sees the container's DNS and network. Another container is addressed by its Compose service name and internal port on a shared network. I probe that name from the tests container itself.
Q: Why is a successful curl not conclusive?
It may run on a different machine, use shell proxy variables, or request a different URL than the browser. I compare the same target and then run a browser smoke test in the failing environment.
Q: Can a timeout increase fix this error?
It cannot make a permanently nonexistent hostname resolvable. I would consider timing only after proving that DNS is intermittently delayed and understanding the resolver or network incident. The first change is to correct the target or connectivity.
Common Mistakes
- Changing
navigationTimeoutbefore checking the failed hostname. A typo will remain a typo after a longer wait. - Assuming
localhostrefers to the host computer from inside a test container. It points to the container's own loopback interface. - Fixing
baseURLwhile the spec still callspage.goto()with an absolute, obsolete domain. - Diagnosing only the initial page URL when an authentication redirect changes the hostname.
- Treating
curlon a laptop as proof that a CI runner or remote browser has the same private DNS access. - Mocking all requests to make a DNS failure disappear. Restrict mocks to dependencies intentionally excluded from the test.
- Using a Docker image tag copied from another project. Match the installed Playwright version and browser binaries.
- Logging complete authenticated URLs. Hostnames usually suffice for DNS triage; protect query strings and credentials.
Conclusion
To fix Playwright net::ERR_NAME_NOT_RESOLVED, identify the actual failed URL, resolve its host where the browser runs, and correct the URL or network path that owns it. Confirm the repair with DNS, HTTP, and a focused Playwright test in that order. Keep the origin explicit in config and CI so the next environment change produces a clear failure instead of a misleading browser timeout.
Interview Questions and Answers
How would you triage net::ERR_NAME_NOT_RESOLVED in a Playwright test?
I capture the exact failed request URL and classify it as a main document, redirect, or subresource. I resolve its hostname where the browser runs, then probe the URL over HTTP. That sequence tells me whether to repair test configuration, app redirects, or network access.
How does ERR_NAME_NOT_RESOLVED differ from ERR_CONNECTION_REFUSED?
Name not resolved means the host could not be mapped to an address. Connection refused means an address was reached but no service accepted the connection at the requested endpoint. I start with DNS for the former and listening host and port for the latter.
What is the relationship between webServer.url and use.baseURL?
webServer.url is Playwright Test's readiness target during setup. use.baseURL resolves relative navigations made by the browser. I keep their origins consistent for a local app and verify both independently when tests use multiple services.
What would you check if a page resolves but login fails with this error?
I inspect the login response and its Location header, then log the browser request sequence. Authentication can redirect to a hostname absent from the test network. I correct the identity callback or canonical-domain setting that emits it.
How would you prove a Docker service name is usable by Playwright?
I run a DNS lookup for the service name inside the Playwright container and request its internal HTTP port from there. I also confirm both services share a Compose network and that the app binds beyond its own loopback interface.
When would you use a proxy in this investigation?
Only when the environment requires a supported proxy to reach the target network. I configure Playwright's proxy setting with the approved server and test navigation in the actual browser. I do not use a proxy to hide a misspelled URL.
Why might a browser request fail after page.goto returns successfully?
The main document can load while scripts, images, or API requests use different origins. I listen for requestfailed, record URL and resource type, and reproduce the interaction that triggers the request. The fix belongs to that secondary origin or its test fixture.
Frequently Asked Questions
What does net::ERR_NAME_NOT_RESOLVED mean in Playwright?
Chromium could not resolve the requested hostname to an address. Inspect the exact failed URL because the name may belong to the page, a redirect, or a subresource. The browser must resolve it from its own network environment.
Why does Playwright show ERR_NAME_NOT_RESOLVED only in CI?
The CI runner may lack a private DNS zone, VPN access, or the correct APP_URL variable. Print and resolve the target hostname in the job, then probe it over HTTP. If the browser runs remotely, repeat the check in that environment.
How do I fix this error in Docker Compose?
Use the app service name and internal port from the tests container, with both services on the same Compose network. Bind the app to 0.0.0.0 so another container can reach it. Verify with a DNS lookup and HTTP request inside the tests service.
Can Playwright baseURL cause a DNS resolution failure?
Yes. Relative navigation such as page.goto("/") is resolved against use.baseURL. Print the effective URL and correct the configured origin; a fully qualified URL in the test bypasses baseURL.
Will increasing Playwright navigation timeout solve ERR_NAME_NOT_RESOLVED?
A longer timeout will not repair a typo or permanently unavailable DNS name. Find the failed hostname and test resolution first. Investigate timing only if evidence shows intermittent resolver or network behavior.
Why does curl work while Playwright fails?
curl may run on another machine, use different proxy variables, or request the initial URL before a redirect. Run the same URL from the browser environment and log Playwright request failures. Compare both the final host and proxy path.
How can I tell whether an asset caused the error?
Listen for page requestfailed events and print the request URL and resource type. If page.goto succeeds but an API or script request fails, fix that secondary origin or narrowly mock an intentionally external dependency.
Related Guides
- How to Fix Playwright "Element is not attached to the DOM"
- How to Fix Playwright locator resolved to hidden element
- How to Fix Playwright waiting for element to be visible enabled and stable
- How to Fix "Cannot find module '@playwright/test'" in Playwright
- How to Fix "Cypress failed to start" and cypress verify Errors
- How to Fix "Playwright Test did not expect test() to be called here"