{"record":{"id":"468136fa003b5ed7","repo":"microsoft/playwright","slug":"selector-engine-name-may-only-contain-a-za-z0-9","errorCode":null,"errorMessage":"Selector engine name may only contain [a-zA-Z0-9_] characters","messagePattern":"Selector engine name may only contain \\[a-zA-Z0-9_\\] characters","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/selectors.ts","lineNumber":60,"sourceCode":"      'internal:has', 'internal:has-not',\n      'internal:has-text', 'internal:has-not-text',\n      'internal:and', 'internal:or', 'internal:chain',\n      '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;","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/selectors.ts#L42-L78","documentation":"Thrown by Selectors.register when the engine name does not match the regex /^[a-zA-Z_0-9-]+$/. The guard ensures selector engine names are safe identifier characters before they are stored and used in selector parsing. Note: the error message text says [a-zA-Z0-9_] but the regex actually permits hyphens as well — a minor doc/string mismatch.","triggerScenarios":"Calling selectors.register(engine) with engine.name containing spaces, colons, dots, unicode, or any character outside [A-Za-z0-9_-]; e.g. registering a custom engine named 'my engine' or 'foo:bar'.","commonSituations":"User-generated or dynamic engine names that were not sanitized; copying an engine name that includes a namespace separator like ':'; whitespace accidentally included in the name string.","solutions":["Rename the engine to use only letters, digits, underscores, and hyphens.","Sanitize the name with name.replace(/[^a-zA-Z0-9_-]/g, '') before registering.","If you need namespacing, use a single hyphen (allowed) rather than a colon."],"exampleFix":"// before\nselectors.register({ name: 'my:engine', query: () => {...} });\n\n// after\nselectors.register({ name: 'my-engine', query: () => {...} });","handlingStrategy":"validation","validationCode":"function sanitizeEngineName(name: string): string {\n  const cleaned = name.replace(/[^a-zA-Z0-9_-]/g, '');\n  if (!cleaned) throw new Error('Engine name is empty after sanitization');\n  return cleaned;\n}\n\nconst name = sanitizeEngineName(rawName);\nselectors.register({ name, query: () => {/*...*/} });","typeGuard":"function isValidEngineName(name: string): boolean {\n  return /^[a-zA-Z_0-9-]+$/.test(name);\n}","tryCatchPattern":null,"preventionTips":["Validate engine names against /^[a-zA-Z_0-9-]+$/ before registering.","Generate engine names from a controlled allow-list of characters.","Avoid whitespace and punctuation (especially colons) in custom engine names."],"tags":["selectors","registration","validation","custom-engine"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}