{"record":{"id":"931cd34fbf881cfe","repo":"grafana/k6","slug":"parsing-wait-for-event-options-w","errorCode":null,"errorMessage":"parsing wait for event options: %w","messagePattern":"parsing wait for event options: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/browser/browser_context_mapping.go","lineNumber":123,"sourceCode":"\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing HTTP credentials: %w\", err)\n\t\t\t}\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, bc.SetHTTPCredentials(creds) //nolint:staticcheck\n\t\t\t}), nil\n\t\t},\n\t\t\"setOffline\": func(offline bool) *sobek.Promise {\n\t\t\treturn promise(vu, func() (any, error) {\n\t\t\t\treturn nil, bc.SetOffline(offline) //nolint:wrapcheck\n\t\t\t})\n\t\t},\n\t\t\"waitForEvent\": func(event string, optsOrPredicate sobek.Value) (*sobek.Promise, error) {\n\t\t\trt := vu.Runtime()\n\t\t\tctx := vu.Context()\n\n\t\t\tpopts, err := parseWaitForEventOptions(rt, optsOrPredicate, bc.Timeout())\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"parsing wait for event options: %w\", err)\n\t\t\t}\n\n\t\t\t// Waits until the first event if no predicate is specified.\n\t\t\tvar pred func(p *common.Page) (bool, error)\n\n\t\t\t// Waits until the event that satisfies the predicate.\n\t\t\tif popts.PredicateFn != nil {\n\t\t\t\tpred = func(p *common.Page) (bool, error) {\n\t\t\t\t\treturn queueTask(ctx, vu.get(ctx, p.TargetID()), func() (bool, error) {\n\t\t\t\t\t\tv, err := popts.PredicateFn(rt.ToValue(p))\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn false, err\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn v.ToBoolean(), nil\n\t\t\t\t\t})()\n\t\t\t\t}\n\t\t\t}\n","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/browser/browser_context_mapping.go#L105-L141","documentation":"browserContext.waitForEvent(event, optsOrPredicate) parses its second argument with parseWaitForEventOptions, which accepts nullish (defaults), a callable predicate function, or an object of {predicate, timeout}. This outer wrapper catches whatever that parser returns: a `predicate` value that is not callable, or an unknown key in the options object. It is thrown synchronously (the mapping returns (nil, err)), not as a rejected promise.","triggerScenarios":"waitForEvent('page', { predicate: 'loaded', timeout: 5000 }) - predicate is a string, not a function; waitForEvent('page', {}) with any unrecognized key; anything Sobek's ToObject turns into a key-bearing wrapper (e.g. a plain string 'load' becomes indexed keys and fails as 'unknown option: 0').","commonSituations":"Naming the predicate by string instead of passing a function; passing an event name or options meant for a different waitForEvent overload; leftover properties from copied Playwright code.","solutions":["Pass a function as the second argument for a plain predicate: waitForEvent('page', (p) => p.url().includes('k6.io'))","Or pass an options object limited to { predicate: fn, timeout: ms }","Read the wrapped cause after the colon - 'predicate function is not callable' vs 'unknown option: X' pinpoints the exact mistake"],"exampleFix":"// before: predicate given as a string\nawait context.waitForEvent('page', { predicate: 'loaded', timeout: 5000 });\n\n// after: predicate is a function\nawait context.waitForEvent('page', {\n  predicate: (page) => page.url().includes('k6.io'),\n  timeout: 5000,\n});","handlingStrategy":"type-guard","validationCode":"const arg = { predicate: (p) => p.url().includes('k6.io'), timeout: 5000 };\nconst callable = (f) => typeof f === 'function';\nif (!(arg == null || callable(arg) || (typeof arg === 'object' && !Array.isArray(arg) &&\n      (arg.predicate === undefined || callable(arg.predicate))))) {\n  throw new TypeError('waitForEvent arg must be a function or { predicate?, timeout? }');\n}\nawait context.waitForEvent('page', arg);","typeGuard":"function isWaitForEventArg(v) {\n  if (v == null || typeof v === 'function') return true;\n  if (typeof v !== 'object' || Array.isArray(v) || typeof v.length === 'number' && v instanceof Array) return false;\n  if (typeof v === 'string') return false;\n  return v.predicate === undefined || typeof v.predicate === 'function';\n}","tryCatchPattern":"try {\n  await context.waitForEvent('page', opts);\n} catch (e) {\n  // thrown synchronously by the mapping, so wrap the call itself\n  if (String(e).includes('parsing wait for event options')) {\n    console.warn('bad waitForEvent options - retrying with defaults');\n    await context.waitForEvent('page');\n  } else throw e;\n}","preventionTips":["Pass a bare function when you only need a predicate","In the object form, predicate must be a function and timeout a number - never strings","Do not pass event names or strings as the second argument"],"tags":["browser","browser-context","wait-for-event","options-parsing"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}