Skip to content

[🐛 Bug]: When taking a screenshot fails, the resulting NameError is misinterpreted as a lack of driver support for screenshots #12799

Closed as not planned

Description

@DanielHeath

What happened?

Chromedriver sometimes returns {value: null} when you GET /session/<id>/screenshot instead of returning a string. I think that's probably a chromedriver bug.

In the selenium ruby bindings, in lib/selenium/webdriver/common/takes_screenshot.rb , any NameError is treated as "driver does not support screenshots".

When nil.unpack1('m') is called (because a null value was returned from chromedriver), this is reported as "driver does not support screenshots. This makes diagnosing the actual issue significantly more difficult!

How can we reproduce the issue?

Use chromedriver

Load a page with an iframe

Switch to the iframe

Take a screenshot

Relevant log output

[53, 62] in /home/daniel/.gem/ruby/3.2.2/gems/selenium-webdriver-4.12.0/lib/selenium/webdriver/common/takes_screenshot.rb
   53:         when :base64
   54:           full_page ? full_screenshot : screenshot
   55:         when :png
   56:           as = screenshot_as(:base64, full_page: full_page)
   57:           debugger unless as
=> 58:           as.unpack1('m')
   59:         else
   60:           raise Error::UnsupportedOperationError, "unsupported format: #{format.inspect}"
   61:         end
   62:       rescue NameError
(byebug) as
nil
(byebug) screenshot_as(:base64, full_page: full_page).length
253940

Operating System

Ubuntu

Selenium version

4.12.0 ruby

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

Chrome 115

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

Chromedriver 115

Are you using Selenium Grid?

No

Activity

  1. added
    I-defectSomething is not working as intended
    A-needs-triagingA Selenium member will evaluate this soon!
    on Sep 21, 2023
  2. github-actions commented on Sep 21, 2023

    @github-actions
    Contributor

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


    Info for maintainers

    Triage this issue by using labels.

    If information is missing, add a helpful comment and then I-issue-template label.

    If the issue is a question, add the I-question label.

    If the issue is valid but there is no time to troubleshoot it, consider adding the help wanted label.

    If the issue requires changes or fixes from an external project (e.g., ChromeDriver, GeckoDriver, MSEdgeDriver, W3C), add the applicable G-* label, and it will provide the correct link and auto-close the issue.

    After troubleshooting the issue, please add the R-awaiting answer label.

    Thank you!

  3. DanielHeath commented on Sep 21, 2023

    @DanielHeath
    Author

    Looking further into this - it appears that if you use Timeout.timeout, the Net::HTTP client used to communicate with chromedriver can get into a broken state.

    This is because Timeout.timeout asynchronously raises an exception in the calling thread, which interrupts operations which were not expected to be able to fail.

    In ruby-3.2.2/lib/ruby/3.2.0/net/http.rb line 1855, the request is written to the socket; on line 1862 the response is read from the socket.

    However, if a timeout exception occurs before the response arrives, the response is not read from the socket. This causes the next request made with that Net::HTTP client to read the response from the interrupted request (since it's queued on the socket and nothing else has read it).

  4. titusfortner commented on Sep 21, 2023

    @titusfortner
    Member

    So what code reproduces this?

    Getting null back from the screenshot endpoint needs to be raised as a bug to Google.
    Http client timeouts should end the session completely.

  5. DanielHeath commented on Sep 22, 2023

    @DanielHeath
    Author

    So far, I can confirm (via mitmproxy) that chromedriver sends the correct response, so no bug needs to be raised to google.

    By step-through debugging with mitmproxy in the other window, I can confirm that net/http returns the wrong response.

    This is fixed if anything causes the socket to be closed and re-opened (eg if at least 2 seconds pass, as that's the keep-alive timeout in net/http).

    Because Timeout uses ::Kernel.catch(instance) and throw(instance), the exception handlers in net/http are skipped.

    I'm still working to get a minimal reproduction on that, but I expect to have it figured out soon.

  6. DanielHeath commented on Sep 22, 2023

    @DanielHeath
    Author

    This is fixed in timeout 0.4.0 (see also rails/rails#29333 , ruby/timeout#30 )

  7. titusfortner commented on Sep 22, 2023

    @titusfortner
    Member

    So this is a bug in net/http? Presumably that is the library that is using the timeout method correctly.

  8. diemol commented on Nov 24, 2023

    @diemol
    Member

    Is there something for us to do here or can this be closed?

  9. titusfortner commented on Nov 25, 2023

    @titusfortner
    Member

    I went down a rabbit hole last time I looked at this trying to parse which libraries were supposed to be doing which things. What I recall is that net/http was the library that people agreed was properly handling the timeout issues. Can the user just require the latest version of timeout for this to work?

  10. titusfortner commented on Jan 20, 2024

    @titusfortner
    Member

    closing as I don't have enough information to know what needs to be done to fix something in selenium code.

  11. DanielHeath commented on Jan 21, 2024

    @DanielHeath
    Author

    There are various ways Timeout can break things unexpectedly.

    However I raised this issue specifically about the use of NameError to check for screenshot support.

    Surely drivers have a way to report screenshot capability other than raising an exception when you try to use them?

    Catching any NameError and assuming it means "no screenshot support" made debugging the code much more difficult, and ruby has e.g. respond_to?(:screenshot)

  12. titusfortner commented on Jan 21, 2024

    @titusfortner
    Member

    Oh, now I get it. I was being more clever than I should be. I changed to explicitly check for it.

  13. github-actions commented on Feb 21, 2024

    @github-actions
    Contributor

    This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

  14. locked and limited conversation to collaborators on Feb 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-rbRuby BindingsI-defectSomething is not working as intendedJ-awaiting answerQuestion asked of user; a reply moves it to triage again

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions