Skip to content

[🐛 Bug]: Selenium driver (C#) doesn't clean up session if timing out when creating session? #14743

@genne

Description

@genne

What happened?

I often encounter timeout errors when attempting to create sessions:

OpenQA.Selenium.WebDriverException: The HTTP request to the remote WebDriver server for URL http://4.207.73.132:4444/wd/hub/session timed out after 60 seconds. 
  ---> System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 60 seconds elapsing. 
  ---> System.TimeoutException: The operation was canceled. 
  ---> System.Threading.Tasks.TaskCanceledException: The operation was canceled. 
  ---> System.IO.IOException: Unable to read data from the transport connection: Operation canceled. 
  ---> System.Net.Sockets.SocketException (125): Operation canceled 
    --- End of inner exception stack trace --- 
    at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken) 
    at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource<System.Int32>.GetResult(Int16 token) 
    at System.Net.Http.HttpConnection.InitialFillAsync(Boolean async) 
    at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) 
    --- End of inner exception stack trace --- 
    at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) 
    at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken) 
    at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) 
    at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) 
    at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken) 
    --- End of inner exception stack trace --- 
    --- End of inner exception stack trace --- 
    at System.Net.Http.HttpClient.HandleFailure(Exception e, Boolean telemetryStarted, HttpResponseMessage response, CancellationTokenSource cts, CancellationToken cancellationToken, CancellationTokenSource pendingRequestsCts) 
    at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken) 
    at OpenQA.Selenium.Remote.HttpCommandExecutor.MakeHttpRequest(HttpRequestInfo requestInfo) 
    at OpenQA.Selenium.Remote.HttpCommandExecutor.ExecuteAsync(Command commandToExecute) 
    --- End of inner exception stack trace --- 
    at OpenQA.Selenium.Remote.HttpCommandExecutor.ExecuteAsync(Command commandToExecute) 
    at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters) 
    at OpenQA.Selenium.WebDriver.StartSession(ICapabilities capabilities) 
    at OpenQA.Selenium.WebDriver..ctor(ICommandExecutor executor, ICapabilities capabilities) 

At the same time, I notice the grid queue builds up, and the sessions seem to run for a couple of minutes before being closed:

image

From analyzing the code, it appears that StartSession doesn’t clean up properly when it fails:

Response response = this.Execute(DriverCommand.NewSession, parameters);

If this throws an exception, the sessionId is never set:

this.sessionId = new SessionId(response.SessionId);

As a result, Dispose does nothing:

if (this.sessionId != null)
    this.Execute(DriverCommand.Quit, (Dictionary<string, object>) null);

The session is still created, but since the session ID is never returned to the client, it remains stuck until it’s automatically terminated after a few minutes. This also causes subsequent sessions to time out as they wait for the hung session, which further compounds the issue by adding more stuck sessions to the queue.

How can we reproduce the issue?

#
    
    [Test]
    public void Timeout()
    {
        var seleniumRemoteUrl = "http://localhost:4444/wd/hub";

        {
            // Create new session
            using var existingSession = new RemoteWebDriver(new(seleniumRemoteUrl), new ChromeOptions());
            
            // Second session will timeout as the first session is still running
            Assert.Throws<WebDriverException>(() =>
                new RemoteWebDriver(new(seleniumRemoteUrl), new ChromeOptions())
            );
            
            // Scope ends, session is closed
        }

        // This now fails as the second session wasn't closed properly
        Assert.DoesNotThrow(() =>
        {
            using var newSession = new RemoteWebDriver(new(seleniumRemoteUrl), new ChromeOptions());
        });
    }

Relevant log output

Expected: No Exception to be thrown
  But was:  <OpenQA.Selenium.WebDriverException: The HTTP request to the remote WebDriver server for URL http://localhost:4444/wd/hub/session timed out after 60 seconds.
 ---> System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 60 seconds elapsing.
 ---> System.TimeoutException: The operation was canceled.
 ---> System.Threading.Tasks.TaskCanceledException: The operation was canceled.
 ---> System.IO.IOException: Unable to read data from the transport connection: Operation canceled.
 ---> System.Net.Sockets.SocketException (89): Operation canceled
   --- End of inner exception stack trace ---
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancellationToken)
   at System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.System.Threading.Tasks.Sources.IValueTaskSource<System.Int32>.GetResult(Int16 token)
   at System.Net.Http.HttpConnection.InitialFillAsync(Boolean async)
   at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
   at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
   at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
   at System.Net.Http.HttpClient.HandleFailure(Exception e, Boolean telemetryStarted, HttpResponseMessage response, CancellationTokenSource cts, CancellationToken cancellationToken, CancellationTokenSource pendingRequestsCts)
   at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
   at OpenQA.Selenium.Remote.HttpCommandExecutor.MakeHttpRequest(HttpRequestInfo requestInfo)
   at OpenQA.Selenium.Remote.HttpCommandExecutor.ExecuteAsync(Command commandToExecute)
   --- End of inner exception stack trace ---
   at OpenQA.Selenium.Remote.HttpCommandExecutor.ExecuteAsync(Command commandToExecute)
   at OpenQA.Selenium.WebDriver.ExecuteAsync(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.StartSession(ICapabilities capabilities)
   at OpenQA.Selenium.WebDriver..ctor(ICommandExecutor executor, ICapabilities capabilities)
   at OpenQA.Selenium.Remote.RemoteWebDriver..ctor(ICommandExecutor commandExecutor, ICapabilities capabilities)
   at OpenQA.Selenium.Remote.RemoteWebDriver..ctor(Uri remoteAddress, ICapabilities capabilities, TimeSpan commandTimeout)
   at OpenQA.Selenium.Remote.RemoteWebDriver..ctor(Uri remoteAddress, ICapabilities capabilities)
   at OpenQA.Selenium.Remote.RemoteWebDriver..ctor(Uri remoteAddress, DriverOptions options)

Operating System

Both macOS 14.6.1 and Linux

Selenium version

C# 4.24.0

What are the browser(s) and version(s) where you see this issue?

Chrome

What are the browser driver(s) and version(s) where you see this issue?

Selenium.WebDriver.ChromeDriver 130.0.6723.11600

Are you using Selenium Grid?

4.26.0 (revision 69f9e5e)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-needs-triagingA Selenium member will evaluate this soon!I-defectSomething is not working as intended

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions