SeleniumHQ/selenium · error · AttributeError
module {__name__!r} has no attribute {name!r}
Error message
module {__name__!r} has no attribute {name!r} What it means
Selenium uses lazy submodule loading for `selenium.webdriver.chrome` via a module-level `__getattr__`. When you access an attribute on the package, it is only resolved if it is one of the registered lazy submodules (options, remote_connection, service, webdriver). Accessing any other name triggers Python's default missing-attribute behavior through this AttributeError. This is the standard mechanism Python uses to defer expensive imports and to report that a requested name simply does not exist on the package.
Source
Thrown at py/selenium/webdriver/chrome/__init__.py:28
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import importlib
_LAZY_SUBMODULES = ["options", "remote_connection", "service", "webdriver"]
def __getattr__(name):
if name in _LAZY_SUBMODULES:
module = importlib.import_module(f".{name}", __name__)
globals()[name] = module
return module
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
def __dir__():
return sorted(_LAZY_SUBMODULES)
View on GitHub (pinned to aa36b38e69)
Solutions
- Import the class directly from its submodule: `from selenium.webdriver.chrome.options import Options`.
- If you only need the WebDriver: use `from selenium.webdriver import Chrome` (re-exported at the top level).
- Check the spelling against the four valid submodules: options, remote_connection, service, webdriver.
- Run `dir(selenium.webdriver.chrome)` to see the valid lazy names.
Example fix
// before
import selenium.webdriver.chrome as chrome
class Opts(chrome.Options): # AttributeError
...
// after
from selenium.webdriver.chrome.options import Options
class Opts(Options):
... Defensive patterns
Strategy: validation
Validate before calling
import selenium.webdriver.chrome as chrome
_VALID = {"options", "remote_connection", "service", "webdriver"}
name = "options"
assert name in _VALID, f"not a lazy submodule of selenium.webdriver.chrome: {name}
options = importlib.import_module(f"selenium.webdriver.chrome.{name}") Type guard
def is_lazy_chrome_submodule(name: str) -> bool:
return name in {"options", "remote_connection", "service", "webdriver"} Try / catch
try:
from selenium.webdriver.chrome.options import Options
except AttributeError as e:
raise ImportError(f"do not access submodules via the package; import directly: {e}") from e Prevention
- Always import classes from their submodule path, never via the package attribute.
- Use `from selenium import webdriver` and `webdriver.Chrome` for the common case.
- Run `dir(selenium.webdriver.chrome)` to list valid lazy names before dynamic access.
When it happens
Trigger: Accessing an attribute on `selenium.webdriver.chrome` that is not in the `_LAZY_SUBMODULES` list, e.g. `selenium.webdriver.chrome.Options` (capital O), `selenium.webdriver.chrome.By`, or a misspelled name like `selenium.webdriver.chrome.webrdiver`. Also triggered by `getattr(selenium.webdriver.chrome, "nonexistent")`.
Common situations: Importing the class wrong: expecting `from selenium import webdriver; webdriver.chrome.Options` to work when it should be `webdriver.ChromeOptions` or `from selenium.webdriver.chrome.options import Options`. Typos after IDE auto-complete. Code written against an older/newer Selenium version where a submodule was renamed or moved. Attempting to reach a remote-only helper from the package root.
Related errors
- module {__name__!r} has no attribute {name!r}
- module {__name__!r} has no attribute {name!r}
- module 'selenium.webdriver' has no attribute {name!r}
- module {__name__!r} has no attribute {name!r}
- module {__name__!r} has no attribute {name!r}
AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14).
Data as JSON: /api/errors/ed91f21e62d685ab.
Report an issue: GitHub.