SeleniumHQ/selenium · error · ValueError

Timeout keys can only be one of the following: implicit, pag

Error message

Timeout keys can only be one of the following: implicit, pageLoad, script

What it means

The timeouts property expects a dict whose keys are a subset of the W3C timeout names: 'implicit', 'pageLoad', 'script'. If any key is outside this set, ValueError is raised. Note it iterates value.keys(), so a non-dict (e.g. a string or None) will raise AttributeError on .keys() before reaching the validation.

Source

Thrown at py/selenium/webdriver/common/options.py:141

    Args:
        timeouts: values in milliseconds for implicit wait, page load and script timeout

    Returns:
        Values for implicit timeout, pageLoad timeout and script timeout if set (in milliseconds)
    """

    def __init__(self, name):
        self.name = name

    def __get__(self, obj, cls):
        return obj._caps.get(self.name)

    def __set__(self, obj, value):
        if all(x in ("implicit", "pageLoad", "script") for x in value.keys()):
            obj.set_capability(self.name, value)
        else:
            raise ValueError("Timeout keys can only be one of the following: implicit, pageLoad, script")


class _ProxyDescriptor:
    """Descriptor for proxy property access.

    Returns:
        Proxy if set, otherwise None.
    """

    def __init__(self, name):
        self.name = name

    def __get__(self, obj, cls):
        return obj._proxy

    def __set__(self, obj, value):
        if not isinstance(value, Proxy):
            raise InvalidArgumentException("Only Proxy objects can be passed in.")

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Use only the keys 'implicit', 'pageLoad', 'script' (camelCase as shown).
  2. Pass a dict, never a bare int or None.
  3. If setting individual timeouts, prefer driver.implicitly_wait() / driver.set_script_timeout() / driver.set_page_load_timeout() instead.

Example fix

# before
options.timeouts = {'page_load': 3000}  # wrong key -> ValueError

# after
options.timeouts = {'pageLoad': 3000, 'implicit': 0}
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = {'implicit','pageLoad','script'}
if not isinstance(value, dict):
    raise TypeError('timeouts must be a dict')
bad = set(value) - ALLOWED
if bad:
    raise ValueError(f'Invalid timeout keys: {bad}; allowed {sorted(ALLOWED)}')
options.timeouts = value

Type guard

ALLOWED = {'implicit','pageLoad','script'}
def is_valid_timeouts(v) -> bool:
    return isinstance(v, dict) and set(v).issubset(ALLOWED)

Try / catch

try:
    options.timeouts = value
except (ValueError, AttributeError):
    options.timeouts = {'pageLoad': value} if isinstance(value, int) else {}

Prevention

When it happens

Trigger: Setting options.timeouts = {'implicit': 5} (correct), but options.timeouts = {'implicit_wait': 5} or {'page_load': 3000} raises. Also passing None or a non-dict crashes on .keys() with AttributeError rather than the friendly ValueError.

Common situations: Using snake_case keys ('page_load', 'implicit_wait') instead of camelCase ('pageLoad'). Passing a single int instead of a dict. Confusing unit expectations (these are raw capability values).

Understand the failure class

Related errors


AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14). Data as JSON: /api/errors/06830de48e6a5995. Report an issue: GitHub.