{"record":{"id":"42e4abdc533305f8","repo":"grafana/k6","slug":"error-while-parsing-selector-selector-canno-42e4ab","errorCode":null,"errorMessage":"Error while parsing selector `${selector}` - cannot use ${operator} in attribute with non-string matching value - ${value}","messagePattern":"Error while parsing selector `(.+?)` - cannot use (.+?) in attribute with non-string matching value - (.+?)","errorType":"exception","errorClass":"InvalidSelectorError","httpStatus":null,"severity":"critical","filePath":"internal/js/modules/k6/browser/common/js/injected_script.js","lineNumber":1125,"sourceCode":"        value += eat1();\n      if (value === \"true\") {\n        value = true;\n      } else if (value === \"false\") {\n        value = false;\n      } else {\n        if (!allowUnquotedStrings) {\n          value = +value;\n          if (Number.isNaN(value))\n            syntaxError(\"parsing attribute value\");\n        }\n      }\n    }\n    skipSpaces();\n    if (next() !== \"]\")\n      syntaxError(\"parsing attribute value\");\n    eat1();\n    if (operator !== \"=\" && typeof value !== \"string\")\n      throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - cannot use ${operator} in attribute with non-string matching value - ${value}`);\n    return { name: jsonPath.join(\".\"), jsonPath, op: operator, value, caseSensitive };\n  }\n  const result = {\n    name: \"\",\n    attributes: []\n  };\n  result.name = readIdentifier();\n  skipSpaces();\n  while (next() === \"[\") {\n    result.attributes.push(readAttribute());\n    skipSpaces();\n  }\n  if (!EOL)\n    syntaxError(void 0);\n  if (!result.name && !result.attributes.length)\n    throw new InvalidSelectorError(`Error while parsing selector \\`${selector}\\` - selector cannot be empty`);\n  return result;\n}","sourceCodeStart":1107,"sourceCodeEnd":1143,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/js/injected_script.js#L1107-L1143","documentation":"A Go panic raised by modules.Register (js/modules/modules.go:17-24) when an extension registers itself under a name that does not start with the constant prefix 'k6/x/'. k6 reserves short internal names for built-in modules, so every externally registered JS module must live under the k6/x/ namespace; the check is a single strings.HasPrefix against extPrefix, and ext.Register then records the module. Because this is a plain panic, the binary (usually a custom xk6 build) aborts when registration runs at startup.","triggerScenarios":"Building a custom k6 binary with xk6 (or a fork) whose extension calls `modules.Register(name, mod)` with a name like 'mycompany/mq', 'k6-mq' or 'mq' — anything missing the leading 'k6/x/'. Happens the moment the generated main initializes the module registry, before any test runs.","commonSituations":"Writing a first xk6 extension and copying a module path convention from npm or Go instead of k6's; renaming an extension without updating the Register call (which also breaks `import 'k6/x/...'` specifiers in scripts); upgrading k6 versions where registration moved to the js/modules API and old boilerplate no longer matches.","solutions":["Prefix the registered name: `modules.Register(\"k6/x/myext\", new(MyExt))`","Update the script import to match exactly: `import myext from 'k6/x/myext';`","Keep the name unique — ext.Register panics separately on duplicates","If wrapping a third-party extension, register under your own k6/x/ name rather than the bare upstream path"],"exampleFix":"// before\nmodules.Register(\"mycompany/mq\", new(MQ)) // panics: missing k6/x/ prefix\n\n// after\nmodules.Register(\"k6/x/mycompany-mq\", new(MQ))\n// in the JS script:\n// import mq from 'k6/x/mycompany-mq';","handlingStrategy":"validation","validationCode":"package main\n\nimport (\n\t\"log\"\n\t\"strings\"\n\n\t\"go.k6.io/k6/v2/js/modules\"\n)\n\nfunc registerExt(name string, mod any) {\n\tconst prefix = \"k6/x/\"\n\tif !strings.HasPrefix(name, prefix) {\n\t\tlog.Fatalf(\"module name %q must be prefixed with %q\", name, prefix)\n\t}\n\tmodules.Register(name, mod)\n}","typeGuard":null,"tryCatchPattern":"// A panic at registration time aborts the custom binary before any test runs;\n// there is no runtime catch — validate names at build/startup instead.\ndefer func() {\n    if r := recover(); r != nil {\n        log.Fatalf(\"extension registration failed: %v\", r)\n    }\n}()\nmodules.Register(name, mod)","preventionTips":["Always register extensions as `k6/x/<name>`; keep the same string in the JS import specifier","Centralize registration in one place instead of scattering Register calls","Add a unit test or startup assert that every registered name has the k6/x/ prefix","Keep names unique across extensions — ext.Register panics on duplicates"],"tags":["xk6","extension","go","registration","panic","modules"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}