{"record":{"id":"0a3d34d7b4ef9389","repo":"grafana/k6","slug":"q-w-0a3d34","errorCode":null,"errorMessage":"%q: %w","messagePattern":"%q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/frame_session.go","lineNumber":644,"sourceCode":"\t\treturn\n\t}\n\tfor _, child := range frameTree.ChildFrames {\n\t\tfs.handleFrameTree(child, initialFrame)\n\t}\n}\n\nfunc (fs *FrameSession) navigateFrame(frame *Frame, url, referrer string) (string, error) {\n\tfs.logger.Debugf(\"FrameSession:navigateFrame\",\n\t\t\"sid:%v fid:%s tid:%v url:%q referrer:%q\",\n\t\tfs.session.ID(), frame.ID(), fs.targetID, url, referrer)\n\n\taction := cdppage.Navigate(url).WithReferrer(referrer).WithFrameID(cdp.FrameID(frame.ID()))\n\t_, documentID, errorText, _, err := action.Do(cdp.WithExecutor(fs.ctx, fs.session))\n\tif err != nil {\n\t\tif errorText == \"\" {\n\t\t\terr = fmt.Errorf(\"%w\", err)\n\t\t} else {\n\t\t\terr = fmt.Errorf(\"%q: %w\", errorText, err)\n\t\t}\n\t}\n\treturn documentID.String(), err\n}\n\nfunc (fs *FrameSession) onConsoleAPICalled(event *cdpruntime.EventConsoleAPICalled) {\n\tl := fs.logger.\n\t\tWithTime(event.Timestamp.Time()).\n\t\tWithField(\"source\", \"browser\").\n\t\tWithField(\"browser_source\", \"console-api\")\n\n\t/* accessing the state Group while not on the eventloop is racy\n\tif s := fs.vu.State(); s.Group.Path != \"\" {\n\t\tl = l.WithField(\"group\", s.Group.Path)\n\t}\n\t*/\n\n\tparsedObjects := make([]string, 0, len(event.Args))","sourceCodeStart":626,"sourceCodeEnd":662,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/frame_session.go#L626-L662","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["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","Wrap goto in try/catch and fail the iteration with a diagnostic instead of crashing the script","Verify the URL opens in a normal browser from the same network before blaming the script"],"exampleFix":"// before\npage.goto('https://tst.example.com'); // throws \"net::ERR_NAME_NOT_RESOLVED\": ...\n\n// after\ntry {\n  page.goto('https://test.example.com', { waitUntil: 'domcontentloaded' });\n} catch (e) {\n  if (/ERR_NAME_NOT_RESOLVED/.test(String(e))) {\n    console.error('DNS failure for test target — check hostname');\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"import dns from 'k6/net/dns'; // optional preflight for DNS-backed failures\n// simpler: verify URL shape before navigating\nfunction assertHttpUrl(u) {\n  if (!/^https?:\\/\\/[^\\s/$.?#].[^\\s]*$/i.test(u)) {\n    throw new Error(`not an absolute http(s) URL: ${u}`);\n  }\n}\nassertHttpUrl(targetUrl);\npage.goto(targetUrl);","typeGuard":"function isNetError(e: unknown, code?: string): e is Error {\n  return e instanceof Error && /net::ERR_/.test(e.message) && (!code || e.message.includes(code));\n}","tryCatchPattern":"try {\n  page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });\n} catch (e) {\n  const msg = String(e);\n  if (msg.includes('ERR_NAME_NOT_RESOLVED')) fail('DNS: ' + url);\n  else if (msg.includes('ERR_CONNECTION_REFUSED')) fail('server down: ' + url);\n  else if (msg.includes('ERR_CERT')) fail('TLS certificate problem: ' + url);\n  else throw e;\n}","preventionTips":["Map each net::ERR_* code to a specific infrastructure check before rerunning","Open the URL in a normal browser from the same host/network first","Set an explicit goto timeout so network hangs surface as timeouts, not hangs"],"tags":["browser","navigation","goto","net-error","network"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}