{"record":{"id":"037c990b439acb9f","repo":"microsoft/playwright","slug":"engine-name-is-a-predefined-selector-engine","errorCode":null,"errorMessage":"\"${engine.name}\" is a predefined selector engine","messagePattern":"\"(.+?)\" is a predefined selector engine","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/selectors.ts","lineNumber":63,"sourceCode":"      'role', 'internal:attr', 'internal:label', 'internal:text',\n      'internal:role', 'internal:testid', 'internal:describe',\n      'aria-ref'\n    ]);\n    this._builtinEnginesInMainWorld = new Set([\n      '_react', '_vue',\n    ]);\n    this._engines = new Map();\n    this._testIdAttributeName = testIdAttributeName ?? 'data-testid';\n    for (const engine of engines)\n      this.register(engine);\n  }\n\n  register(engine: channels.SelectorEngine) {\n    if (!engine.name.match(/^[a-zA-Z_0-9-]+$/))\n      throw new Error('Selector engine name may only contain [a-zA-Z0-9_] characters');\n    // Note: we keep 'zs' for future use.\n    if (this._builtinEngines.has(engine.name) || engine.name === 'zs' || engine.name === 'zs:light')\n      throw new Error(`\"${engine.name}\" is a predefined selector engine`);\n    if (this._engines.has(engine.name))\n      throw new Error(`\"${engine.name}\" selector engine has been already registered`);\n    this._engines.set(engine.name, engine);\n  }\n\n  testIdAttributeName(): string {\n    return this._testIdAttributeName;\n  }\n\n  setTestIdAttributeName(testIdAttributeName: string) {\n    this._testIdAttributeName = testIdAttributeName;\n  }\n\n  parseSelector(selector: string | ParsedSelector, strict: boolean) {\n    const parsed = typeof selector === 'string' ? parseSelector(selector) : selector;\n    let needsMainWorld = false;\n    visitAllSelectorParts(parsed, part => {\n      const name = part.name;","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/selectors.ts#L45-L81","documentation":"Thrown by Selectors.register when the engine name collides with a predefined/builtin engine. The check covers everything in _builtinEngines (css, xpath, text, role, internal:*, data-testid variants, etc.) plus the reserved names 'zs' and 'zs:light' kept for future use. Registering over a builtin would break core selector resolution, so it is rejected outright.","triggerScenarios":"Calling selectors.register with a name like 'css', 'xpath', 'text', 'role', 'internal:has', 'data-testid', or the reserved 'zs'/'zs:light'.","commonSituations":"Unaware that a name is builtin; dynamically generating engine names without checking the builtin set; trying to override the text/role engine behavior.","solutions":["Choose a non-builtin, non-reserved name for your custom engine.","If you intended to extend a builtin, register a new engine with a distinct name and use that engine prefix in your selectors.","Check the _builtinEngines list in the source before naming your engine."],"exampleFix":"// before\nselectors.register({ name: 'text', query: () => {...} });\n\n// after\nselectors.register({ name: 'my-text', query: () => {...} });","handlingStrategy":"validation","validationCode":"const BUILTIN_ENGINES = new Set([\n  'css','css:light','xpath','xpath:light','_react','_vue',\n  'text','text:light','id','id:light','role','nth','visible',\n  'internal:control','internal:has','internal:has-not','internal:has-text',\n  'internal:has-not-text','internal:and','internal:or','internal:chain',\n  'internal:attr','internal:label','internal:text','internal:role',\n  'internal:testid','internal:describe','aria-ref','zs','zs:light'\n]);\n\nif (BUILTIN_ENGINES.has(name)) throw new Error(`${name} is a builtin engine`);","typeGuard":"function isBuiltinEngine(name: string): boolean {\n  const builtins = ['css','xpath','text','role','nth','visible','id','aria-ref','zs','zs:light'];\n  return builtins.includes(name) || name.startsWith('internal:') || name.endsWith(':light');\n}","tryCatchPattern":null,"preventionTips":["Namespace custom engine names with a unique prefix unlikely to collide with builtins.","Cross-check a candidate name against the builtin list in selectors.ts before registering.","Avoid overriding builtin engines; extend functionality under a new name instead."],"tags":["selectors","registration","builtin","collision","custom-engine"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}