{"record":{"id":"34024e37cad3eadb","repo":"grafana/k6","slug":"evaluating-pattern-w","errorCode":null,"errorMessage":"evaluating pattern: %w","messagePattern":"evaluating pattern: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/browser/helpers.go","lineNumber":80,"sourceCode":"\treturn args\n}\n\n// sobekEmptyString returns true if a given value is not nil or an empty string.\nfunc sobekEmptyString(v sobek.Value) bool {\n\treturn k6common.IsNullish(v) || strings.TrimSpace(v.String()) == \"\"\n}\n\n// newRegExMatcher returns a function that runs in the JS runtime's event loop\n// for pattern matching. It uses ECMAScript RegEx engine for consistency.\n//\n// It's safe to call this function off of the event loop since the returned\n// function gets run in the task queue, ensuring it runs on the event loop.\nfunc newRegExMatcher(ctx context.Context, vu moduleVU, tq *taskqueue.TaskQueue) common.RegExMatcher {\n\treturn func(pattern, str string) (bool, error) {\n\t\treturn queueTask(ctx, tq, func() (bool, error) {\n\t\t\tv, err := vu.Runtime().RunString(pattern + `.test('` + str + `')`)\n\t\t\tif err != nil {\n\t\t\t\treturn false, fmt.Errorf(\"evaluating pattern: %w\", err)\n\t\t\t}\n\t\t\treturn v.ToBoolean(), nil\n\t\t})()\n\t}\n}\n\n// promise runs fn in a goroutine and returns a new sobek.Promise.\n//   - If fn returns a nil error, resolves the promise with the\n//     first result value fn returns.\n//   - Otherwise, rejects the promise with the error fn returns.\nfunc promise(vu moduleVU, fn func() (result any, reason error)) *sobek.Promise {\n\tp, resolve, reject := promises.New(vu)\n\tgo func() {\n\t\tv, err := fn()\n\t\tif err != nil {\n\t\t\treject(k6ext.BrowserError(err))\n\t\t\treturn\n\t\t}","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/grafana/k6/blob/01ffac6f245854c1b8adc6a69857c76a15f90022/internal/js/modules/k6/browser/browser/helpers.go#L62-L98","documentation":"Produced by newRegExMatcher (browser/helpers.go:80): it builds the snippet `pattern + \".test('\" + str + \"')\"` and runs it on the sobek runtime, wrapping any failure as 'evaluating pattern'. This matcher backs URL/pattern matching in page.waitForURL, page/frame.waitForNavigation({ url }), page.waitForRequest, page.waitForResponse and page.route. Quoted-string patterns are compared literally and never reach the regex engine; everything else is executed as an ECMAScript regex source, so an invalid regex (unbalanced parens/brackets) or a URL containing an apostrophe breaks the generated expression.","triggerScenarios":"page.waitForURL(\"**/it's-done\") — the apostrophe in the matched URL terminates the string literal in the generated snippet; page.route('api(v1', handler) — invalid regex source; passing glob strings containing (, [ or quotes where a RegExp is expected; page.waitForRequest(\"/search?q='k6'\").","commonSituations":"Using Playwright glob patterns verbatim (k6 evaluates many of them as raw regex sources); localizing tests against URLs with apostrophes (Italian/French pages); patterns built by string concatenation that forget regex escaping.","solutions":["Pass a real RegExp object instead of a glob string: page.waitForURL(/\\/q='k6'/)","Escape regex metacharacters in dynamic patterns before passing them","Avoid patterns and expected URLs containing single quotes, or match on a quote-free substring","Pre-validate the pattern in JS with new RegExp(...) before the call"],"exampleFix":"// before\npage.waitForURL(\"**/results?q='k6'\"); // apostrophes/glob break the generated regex\n// after\npage.waitForURL(/\\/results\\?q='k6'/);","handlingStrategy":"validation","validationCode":"function assertValidPattern(p) {\n  if (typeof p === 'string') { new RegExp(p); return; } // throws SyntaxError if invalid\n  if (p instanceof RegExp) return;\n  throw new Error('pattern must be a string or RegExp');\n}\nassertValidPattern(pattern); // before waitForURL/waitForNavigation/route\n// avoid single quotes in matched URLs; match on a quote-free substring instead","typeGuard":"function isUsablePattern(p) {\n  if (p instanceof RegExp) return true;\n  if (typeof p !== 'string') return false;\n  if (p.includes(\"'\")) return false;\n  try { new RegExp(p); return true; } catch { return false; }\n}","tryCatchPattern":"try { await page.waitForURL(pattern, { timeout: 5000 }); } catch (e) { if (!String(e.message).includes('evaluating pattern')) throw e; /* fall back to an exact quoted URL */ }","preventionTips":["Prefer RegExp literals (/\\/api\\/v1\\//) over glob strings for URL matching","Never embed raw URLs containing apostrophes into patterns; match a clean substring","Escape regex metacharacters in dynamically built patterns","Keep patterns in one place so they can be smoke-tested with new RegExp at script start"],"tags":["k6","k6-browser","regex","url-matching","wait-for-url","route"],"backgroundTag":"invalid-regex-pattern","analyzedSha":"01ffac6f245854c1b8adc6a69857c76a15f90022","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}