{"record":{"id":"038de26a4f2f2591","repo":"SeleniumHQ/selenium","slug":"compound-class-names-are-not-allowed-038de2","errorCode":null,"errorMessage":"Compound class names are not allowed.","messagePattern":"Compound class names are not allowed\\.","errorType":"validation","errorClass":"InvalidSelectorException","httpStatus":null,"severity":"error","filePath":"py/selenium/webdriver/remote/shadowroot.py","lineNumber":81,"sourceCode":"                - By.CSS_SELECTOR: Locate by a CSS selector.\n                - By.CLASS_NAME: Locate by the `class` attribute.\n                - By.TAG_NAME: Locate by the tag name (e.g., \"input\", \"button\").\n                - By.LINK_TEXT: Locate a link element by its exact text.\n                - By.PARTIAL_LINK_TEXT: Locate a link element by partial text match.\n            value: The locator value to use with the specified `by` strategy.\n\n        Returns:\n            The first matching `WebElement` found on the page.\n\n        Example:\n            >>> element = driver.find_element(By.ID, \"foo\")\n        \"\"\"\n        if by == By.ID:\n            by = By.CSS_SELECTOR\n            value = f'[id=\"{value}\"]'\n        elif by == By.CLASS_NAME:\n            if value and any(char.isspace() for char in value.strip()):\n                raise InvalidSelectorException(\"Compound class names are not allowed.\")\n            by = By.CSS_SELECTOR\n            value = f\".{value}\"\n        elif by == By.NAME:\n            by = By.CSS_SELECTOR\n            value = f'[name=\"{value}\"]'\n\n        return self._execute(Command.FIND_ELEMENT_FROM_SHADOW_ROOT, {\"using\": by, \"value\": value})[\"value\"]\n\n    def find_elements(self, by: str | By = By.ID, value: str | None = None) -> list[WebElement]:\n        \"\"\"Find elements inside a shadow root given a By strategy and locator.\n\n        Args:\n            by: The locating strategy to use. Default is `By.ID`. Supported values include:\n                - By.ID: Locate by element ID.\n                - By.NAME: Locate by the `name` attribute.\n                - By.XPATH: Locate by an XPath expression.\n                - By.CSS_SELECTOR: Locate by a CSS selector.\n                - By.CLASS_NAME: Locate by the `class` attribute.","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/SeleniumHQ/selenium/blob/aa36b38e696a0909e973bdf5e2f9031ffe842c4b/py/selenium/webdriver/remote/shadowroot.py#L63-L99","documentation":"Raised inside `ShadowRoot.find_element` when `by == By.CLASS_NAME` and the value contains internal whitespace after stripping (e.g. 'foo bar'). The shadow-root API converts CLASS_NAME into a CSS selector (`.value`), but a multi-class string is not a valid single CSS class, so it rejects it preemptively. It is an InvalidSelectorException.","triggerScenarios":"Calling `shadow_root.find_element(By.CLASS_NAME, 'btn primary')` or any value with embedded spaces/tabs. Whitespace at the ends is stripped first, so only inner whitespace triggers it.","commonSituations":"Selecting elements that carry several classes by passing the full class attribute string; copying the className straight from HTML into the locator.","solutions":["Use By.CSS_SELECTOR with a compound selector: '.btn.primary'.","If you only need one distinguishing class, pass that single class name to CLASS_NAME.","Switch to By.XPATH if the multi-class match is complex."],"exampleFix":"# before\nshadow_root.find_element(By.CLASS_NAME, 'btn primary')\n\n# after\nshadow_root.find_element(By.CSS_SELECTOR, '.btn.primary')","handlingStrategy":"validation","validationCode":"if by == By.CLASS_NAME and value and any(c.isspace() for c in value.strip()):\n    raise InvalidSelectorException('use By.CSS_SELECTOR for compound classes, e.g. .a.b')","typeGuard":"def is_single_class_name(value: str) -> bool:\n    return not (value and any(c.isspace() for c in value.strip()))","tryCatchPattern":null,"preventionTips":["Never paste a multi-class attribute into CLASS_NAME; build a CSS selector instead.","Centralize locators so compound classes are caught in review."],"tags":["locator","validation","shadow-root"],"backgroundTag":null,"analyzedSha":"aa36b38e696a0909e973bdf5e2f9031ffe842c4b","analyzedAt":"2026-08-14T02:32:32.244Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}