Skip to content

[🐛 Bug]: Timeout env variable GLOBAL_DEFAULT_TIMEOUT has no effect #15604

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
justinjosephmkj opened this issue Apr 9, 2025 · 17 comments · Fixed by #15673
Closed

[🐛 Bug]: Timeout env variable GLOBAL_DEFAULT_TIMEOUT has no effect #15604

justinjosephmkj opened this issue Apr 9, 2025 · 17 comments · Fixed by #15673
Labels
C-py Python Bindings I-defect Something is not working as intended I-regression Something was working but we "fixed" it

Comments

@justinjosephmkj
Copy link

justinjosephmkj commented Apr 9, 2025

Description

The timeout is always set to 120 seconds, the env variable has GLOBAL_DEFAULT_TIMEOUT has no effect.

https://github.com/SeleniumHQ/selenium/blob/ecb0dbf91415b10d718acf28afefc16654a9f13a/py/selenium/webdriver/chromium/remote_connection.py#L33

client_config = client_config or ClientConfig( remote_server_addr=remote_server_addr, keep_alive=keep_alive, timeout=120 )

https://github.com/SeleniumHQ/selenium/blob/ecb0dbf91415b10d718acf28afefc16654a9f13a/py/selenium/webdriver/remote/client_config.py#L107
self.timeout = ( ( float(os.getenv("GLOBAL_DEFAULT_TIMEOUT", str(socket.getdefaulttimeout()))) if os.getenv("GLOBAL_DEFAULT_TIMEOUT") is not None else socket.getdefaulttimeout() ) if timeout is None else timeout )

Others:
https://github.com/SeleniumHQ/selenium/blob/ecb0dbf91415b10d718acf28afefc16654a9f13a/py/selenium/webdriver/firefox/remote_connection.py#L35
https://github.com/SeleniumHQ/selenium/blob/ecb0dbf91415b10d718acf28afefc16654a9f13a/py/selenium/webdriver/safari/remote_connection.py#L35

Reproducible Code

driver.get("https://github.com/")
driver.implicitly_wait(130)
field = driver.find_element(By.ID, "qwertyzxcvb")

Debugging Logs

/site-packages/urllib3/connectionpool.py", line 369, in _raise_timeout
    raise ReadTimeoutError(
urllib3.exceptions.ReadTimeoutError: HTTPConnectionPool(host='localhost', port=123): Read timed out. (read timeout=120)
@justinjosephmkj justinjosephmkj added A-needs-triaging A Selenium member will evaluate this soon! I-defect Something is not working as intended labels Apr 9, 2025
@selenium-ci
Copy link
Member

@justinjosephmkj, thank you for creating this issue. We will troubleshoot it as soon as we can.

Selenium Triage Team: remember to follow the Triage Guide

@github-actions github-actions bot added C-py Python Bindings I-regression Something was working but we "fixed" it OS-linux labels Apr 9, 2025
@cgoldberg cgoldberg removed the A-needs-triaging A Selenium member will evaluate this soon! label Apr 10, 2025
@cgoldberg
Copy link
Contributor

Thanks for reporting this.

I just confirmed that GLOBAL_DEFAULT_TIMEOUT is not respected.


Some notes:

The logic for setting timeout inside ClientConfig (in py/selenium/webdriver/remote/remote_connection.py) currently looks like this:

self.timeout = (
    (
        float(os.getenv("GLOBAL_DEFAULT_TIMEOUT", str(socket.getdefaulttimeout())))
        if os.getenv("GLOBAL_DEFAULT_TIMEOUT") is not None
        else socket.getdefaulttimeout()
    )
    if timeout is None
    else timeout
)

This sets the value to whatever is passed in when the class is initialized, even if GLOBAL_DEFAULT_TIMEOUT is already set. That needs to be fixed.

The existing logic will also break if:

  • you set GLOBAL_DEFAULT_TIMEOUT to any value that can't be converted to a float.
  • you don't set GLOBAL_DEFAULT_TIMEOUT, but a socket timeout has been set previously.

... so those need to be considered when fixing.

The reset_timeout() method also needs to be fixed to consider the case when GLOBAL_DEFAULT_TIMEOUT is set.

@shbenzer shbenzer added the good first issue Good first issue for new contributors to start with label Apr 10, 2025
@XueSongTap
Copy link

Can I work on this ?

@cgoldberg
Copy link
Contributor

@XueSongTap yea, of course. Submit a Pull Request with the fix and link it to this issue.

You should probably add some tests for this too.

If you have any questions about contributing or anything else, you can submit a draft pull request and tag me in the comments.. or ask anyone for help in the Slack channel:

https://www.selenium.dev/support/#ChatRoom

@Pikamander2
Copy link

Pikamander2 commented Apr 16, 2025

@cgoldberg @XueSongTap - I'm not sure if this is 100% the same issue, but it seems related enough to mention.

Occasionally, I deal with web pages that have absurdly long page generation times that I have no control over. By default, Selenium's read timeout is 120 seconds, which isn't always long enough.

Here's a Python function that I've been using to dynamically increase/decrease the timeout from 120 seconds to whatever amount of time I need:

def change_selenium_read_timeout(driver, seconds):
    driver.command_executor.set_timeout(seconds)

Here's an example of how I use it:

change_selenium_read_timeout(driver, 5000)
driver.get(slow_url)
change_selenium_read_timeout(driver, 120)

My function works correctly, but throws a deprecation warning:

DeprecationWarning: set_timeout() in RemoteConnection is deprecated, set timeout to ClientConfig instance in constructor instead

I don't quite understand what I'm supposed to do here and couldn't find much relevant documentation. Is there a simple drop-in replacement for the driver.command_executor.set_timeout line? Can the timeout still be set dynamically as needed rather than only when the driver is first created?

@titusfortner
Copy link
Member

titusfortner commented Apr 16, 2025

Where does GLOBAL_DEFAULT_TIMEOUT come from? Is it a standard Python thing? There are so many different timeouts in testing that it seems overly vague. Also, "default" means that it should be able to be overridden in the code, not the thing that should be used whenever it is set. Which isn't to say the logic as it is now is correct, just that the intention of that variable is not at all clear, and we need to make sure we fix this the right way if what we have now isn't working.

@titusfortner
Copy link
Member

titusfortner commented Apr 16, 2025

@Pikamander2 it is a frustrating thing that the default Page Load Timeout value is much greater than the default read timeout values of all the http clients out there. Unless you change a setting you can never get a page load timeout. If you really need longer than 2 minutes for a page to load (and if so, I'm really sorry you work wherever you work), you can change it here: https://www.selenium.dev/documentation/webdriver/drivers/http_client/

@cgoldberg
Copy link
Contributor

GLOBAL_DEFAULT_TIMEOUT is an environment variable only used in the Python bindings. It was added last year in #14354.

"default" means that it should be able to be overridden in the code, not the thing that should be used whenever it is set.

Typically you would set an environment variable to override something set in code... otherwise it would be pretty useless. So maybe it should be named better (SE_TIMEOUT is already used by Selenium Manager), but I think the intention is to override the timeouts set in code. However, I agree that there are a ton of timeouts throughout the codebase and it's not at all clear which one this is setting.

In #15628 that is up for review, it defines the behavior as:

  1. Use GLOBAL_DEFAULT_TIMEOUT if it's set in the environment
  2. Otherwise, use the explicitly provided timeout parameter
  3. Fall back to socket.getdefaulttimeout() if neither is available

To me, that sounds correct.

AFAIK, it isn't even documented anywhere, so I have no idea how people could know about it without diving into the code.

@titusfortner
Copy link
Member

Ah, looks like this is the same issue as #15620

So this makes sense: socket._GLOBAL_DEFAULT_TIMEOUT, a private constant in the socket package that can be overridden with socket.setdefaulttimeout(). This never should have been an environment variable.

Aha, no, it comes from this #14696
@VietND96 does Appium need that global variable?

The right way to do this is to just do socket.setdefaulttimeout() before you start the test.
If you need it to come from an environment variable, then it can be pulled in client code, not Selenium code.

@VietND96
Copy link
Member

@titusfortner
Copy link
Member

@KazuCocoa can we deprecate this environment variable and have people use socket.setdefaulttimeout(), or pass in the value? It is not obvious what timeout this applies to, and it doesn't make sense for a Default value to override a value passed in.

What do you think is best for this?

@titusfortner titusfortner added A-needs decision TLC needs to discuss and agree and removed good first issue Good first issue for new contributors to start with labels Apr 17, 2025
@KazuCocoa
Copy link
Contributor

Yes, it's fine for us to deprecate/remove it. We just put that from selenium bindings. We'll update the documentation when it gets deprecated/removed.

@cgoldberg
Copy link
Contributor

So should we deprecate GLOBAL_DEFAULT_TIMEOUT or just remove it? It's undocumented and it would be less work to just remove it.

@titusfortner
Copy link
Member

I forgot that it's not actually working right now. Would it make sense to check if someone is trying to use it and throw a warning saying to use setdefaulttimeout()? I'm ok just deleting it, too, depends on how I'm feeling in any given moment the route I'd go. 😂

@cgoldberg
Copy link
Contributor

I'd prefer to remove it so we don't have to remember to remove the warning eventually. Since it doesn't currently work, nobody would be any worse off than they are today.

@titusfortner titusfortner added R-help wanted Issues looking for contributions and removed A-needs decision TLC needs to discuss and agree labels Apr 18, 2025
@selenium-ci
Copy link
Member

This issue is looking for contributors.

Please comment below or reach out to us through our IRC/Slack/Matrix channels if you are interested.

@cgoldberg
Copy link
Contributor

@Pikamander2

I don't quite understand what I'm supposed to do here and couldn't find much relevant documentation.

I just opened #15672 that is related to your issue.

Is there a simple drop-in replacement for the driver.command_executor.set_timeout line? Can the timeout still be set dynamically as needed rather than only when the driver is first created?

You should be able to do this:

driver.command_executor._client_config.timeout = 5000

If #15672 gets implemented, you could then do:

driver.command_executor.client_config.timeout = 5000

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-py Python Bindings I-defect Something is not working as intended I-regression Something was working but we "fixed" it
Projects
None yet
9 participants