{"record":{"id":"23d775f1d03b1ca5","repo":"grafana/k6","slug":"parsing-browser-newcontext-options-w","errorCode":null,"errorMessage":"parsing browser.newContext options: %w","messagePattern":"parsing browser\\.newContext options: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/browser/browser_mapping.go","lineNumber":47,"sourceCode":"\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tb, err := browser()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\treturn nil, b.CloseContext() //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"isConnected\": func() (bool, error) {\n\t\t\tb, err := browser()\n\t\t\tif err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\t\treturn b.IsConnected(), nil\n\t\t},\n\t\t\"newContext\": func(opts sobek.Value) (*sobek.Promise, error) {\n\t\t\tpopts, err := parseBrowserContextOptions(vu.Runtime(), opts)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing browser.newContext options: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\tb, err := browser()\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\t\t\t\tbctx, err := b.NewContext(popts)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err //nolint:wrapcheck\n\t\t\t\t}\n\t\t\t\tif err := initBrowserContext(bctx, vu.testRunID); err != nil {\n\t\t\t\t\treturn nil, err\n\t\t\t\t}\n\n\t\t\t\treturn mapBrowserContext(vu, bctx), nil\n\t\t\t}), nil\n\t\t},\n\t\t\"userAgent\": func() (string, error) {","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/browser/browser_mapping.go#L29-L65","documentation":"browser.newContext(opts) parses its argument with parseBrowserContextOptions: default BrowserContextOptions are merged with the passed value via Sobek ExportTo (mergeWith), then ProxyOptions.Validate runs (proxy.server must be set when a proxy object is given). This outer wrapper catches any failure in that pipeline - a struct export error for wrong field types, or 'proxy.server must be set'.","triggerScenarios":"newContext({ viewport: '1280x720' }) - viewport must be {width, height} numbers; newContext({ ignoreHTTPSErrors: 'yes' }) - must be boolean; newContext({ proxy: { username: 'u' } }) - proxy without server fails validation; any value Sobek cannot export onto the options struct.","commonSituations":"Passing launch-time options (executablePath, headless) to newContext by mistake; stringified booleans/numbers from env-driven config; partial proxy configuration copied from system settings.","solutions":["Match the documented BrowserContextOptions shape: viewport/screen as {width, height} numbers, booleans as real booleans, strings for locale/userAgent","If passing proxy, always include server (e.g. { server: 'http://proxyhost:3128' })","Read the wrapped cause after the colon - the ExportTo error names the offending field"],"exampleFix":"// before: wrong shapes for viewport and ignoreHTTPSErrors\nconst ctx = await browser.newContext({\n  viewport: '1280x720',\n  ignoreHTTPSErrors: 'true',\n});\n\n// after: correct types\nconst ctx = await browser.newContext({\n  viewport: { width: 1280, height: 720 },\n  ignoreHTTPSErrors: true,\n});","handlingStrategy":"type-guard","validationCode":"// validate the shape before calling newContext\nfunction validContextOptions(o = {}) {\n  const num = (v) => typeof v === 'number';\n  if (o.viewport !== undefined && !(num(o.viewport.width) && num(o.viewport.height))) return false;\n  if (o.screen !== undefined && !(num(o.screen.width) && num(o.screen.height))) return false;\n  if (o.ignoreHTTPSErrors !== undefined && typeof o.ignoreHTTPSErrors !== 'boolean') return false;\n  if (o.proxy !== undefined && (typeof o.proxy.server !== 'string' || !o.proxy.server)) return false;\n  return true;\n}\nif (!validContextOptions(opts)) throw new TypeError('bad browser context options');\nconst ctx = await browser.newContext(opts);","typeGuard":"interface Viewport { width: number; height: number }\ninterface ContextOpts {\n  viewport?: Viewport;\n  screen?: Viewport;\n  ignoreHTTPSErrors?: boolean;\n  locale?: string;\n  userAgent?: string;\n  deviceScaleFactor?: number;\n  proxy?: { server: string; bypass?: string };\n}\nfunction isContextOpts(v: unknown): v is ContextOpts {\n  const o = v as ContextOpts;\n  const vp = (x?: Viewport) => x == null || (typeof x.width === 'number' && typeof x.height === 'number');\n  return (\n    v != null && typeof v === 'object' && vp(o.viewport) && vp(o.screen) &&\n    (o.ignoreHTTPSErrors == null || typeof o.ignoreHTTPSErrors === 'boolean') &&\n    (o.proxy == null || typeof o.proxy.server === 'string')\n  );\n}","tryCatchPattern":"try {\n  ctx = await browser.newContext(opts);\n} catch (e) {\n  if (String(e).includes('parsing browser.newContext options')) {\n    // fall back to defaults, then apply only the subset you know is valid\n    ctx = await browser.newContext();\n  } else throw e;\n}","preventionTips":["Keep one typed constants file for context options reused across tests","Coerce env-derived values (booleans, numbers) before passing them in","Never pass launch options (headless, executablePath) to newContext - they belong to browser launch/scenario options"],"tags":["browser","browser-context","new-context","options-parsing","proxy"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}