grafana/k6 · error

%q: %w

Error message

%q: %w

What it means

FrameSession.navigateFrame (frame_session.go:644) sends Page.navigate and, when chromium returns both a CDP error and a non-empty errorText, formats the result as "<errorText>": <cdp error>. The quoted part is chromium's own navigation failure reason, typically net::ERR_* codes such as ERR_NAME_NOT_RESOLVED, ERR_CONNECTION_REFUSED, ERR_CERT_AUTHORITY_INVALID, or net::ERR_ABORTED on downloads/redirects. This is the error users see from page.goto()/frame.goto() when navigation itself fails.

Source

Thrown at internal/js/modules/k6/browser/common/frame_session.go:644

		return
	}
	for _, child := range frameTree.ChildFrames {
		fs.handleFrameTree(child, initialFrame)
	}
}

func (fs *FrameSession) navigateFrame(frame *Frame, url, referrer string) (string, error) {
	fs.logger.Debugf("FrameSession:navigateFrame",
		"sid:%v fid:%s tid:%v url:%q referrer:%q",
		fs.session.ID(), frame.ID(), fs.targetID, url, referrer)

	action := cdppage.Navigate(url).WithReferrer(referrer).WithFrameID(cdp.FrameID(frame.ID()))
	_, documentID, errorText, _, err := action.Do(cdp.WithExecutor(fs.ctx, fs.session))
	if err != nil {
		if errorText == "" {
			err = fmt.Errorf("%w", err)
		} else {
			err = fmt.Errorf("%q: %w", errorText, err)
		}
	}
	return documentID.String(), err
}

func (fs *FrameSession) onConsoleAPICalled(event *cdpruntime.EventConsoleAPICalled) {
	l := fs.logger.
		WithTime(event.Timestamp.Time()).
		WithField("source", "browser").
		WithField("browser_source", "console-api")

	/* accessing the state Group while not on the eventloop is racy
	if s := fs.vu.State(); s.Group.Path != "" {
		l = l.WithField("group", s.Group.Path)
	}
	*/

	parsedObjects := make([]string, 0, len(event.Args))

View on GitHub (pinned to 93accf6570)

Solutions

  1. Match the net::ERR_* code to the cause: DNS (ERR_NAME_NOT_RESOLVED) → check hostname/resolver; connection (ERR_CONNECTION_REFUSED/TIMED_OUT) → is the server up; cert (ERR_CERT_AUTHORITY_INVALID) → fix or allow the cert
  2. Wrap goto in try/catch and fail the iteration with a diagnostic instead of crashing the script
  3. Verify the URL opens in a normal browser from the same network before blaming the script

Example fix

// before
page.goto('https://tst.example.com'); // throws "net::ERR_NAME_NOT_RESOLVED": ...

// after
try {
  page.goto('https://test.example.com', { waitUntil: 'domcontentloaded' });
} catch (e) {
  if (/ERR_NAME_NOT_RESOLVED/.test(String(e))) {
    console.error('DNS failure for test target — check hostname');
  }
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

import dns from 'k6/net/dns'; // optional preflight for DNS-backed failures
// simpler: verify URL shape before navigating
function assertHttpUrl(u) {
  if (!/^https?:\/\/[^\s/$.?#].[^\s]*$/i.test(u)) {
    throw new Error(`not an absolute http(s) URL: ${u}`);
  }
}
assertHttpUrl(targetUrl);
page.goto(targetUrl);

Type guard

function isNetError(e: unknown, code?: string): e is Error {
  return e instanceof Error && /net::ERR_/.test(e.message) && (!code || e.message.includes(code));
}

Try / catch

try {
  page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
} catch (e) {
  const msg = String(e);
  if (msg.includes('ERR_NAME_NOT_RESOLVED')) fail('DNS: ' + url);
  else if (msg.includes('ERR_CONNECTION_REFUSED')) fail('server down: ' + url);
  else if (msg.includes('ERR_CERT')) fail('TLS certificate problem: ' + url);
  else throw e;
}

Prevention

When it happens

Trigger: page.goto() to a hostname that does not resolve (DNS failure), a server that is down/refusing connections, a self-signed or expired TLS certificate, a URL with a bad scheme, or net::ERR_ABORTED when the navigation is interrupted (download triggered, JS redirect during load).

Common situations: Testing against not-yet-deployed environments, corporate proxies/DNS that block the test target, certificate issues on staging hosts, and load-induced connection failures where the origin stops accepting connections.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/0a3d34d7b4ef9389. Report an issue: GitHub.