'Browser.close' wasn't found. How to kill headless chrome?

1,931 views
Skip to first unread message

Timothy McCurrach

unread,
Dec 21, 2017, 5:13:54 PM12/21/17
to chrome-debugging-protocol
Hi All,

I am running a python script which launches an instance of headless chrome, and uses PyChromeDevTools wrapper for the devtools protocol to interact with it. Everything works as expected, apart from Browser.close.

Browser.getVersion returns the following:
{'protocolVersion': '1.2', 'product': 'HeadlessChrome/63.0.3239.108', 'revision': '@d2626860fae283daee484943e6820af18fc73fd9', 'userAgent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/63.0.3239.108 Safari/537.36', 'jsVersion': '6.3.292.48'}

However with Browser.close gives the following error:
{'error': {'code': -32601, 'message': "'Browser.close' wasn't found"}

A minimal script would be the following:
import PyChromeDevTools
chrome = PyChromeDevTools.ChromeInterface()
chrome.Page.navigate(url="https://www.google.com/")
chrome.Browser.close()

(As it is set up PyChromeDevTools actually doesn't return anything, but a little but if you print the returned error, this is what you get). I've also tried this using Chrome 64 Beta and it doesn't seem to make any difference.

I appologise if this isn't the appropriate channel to post something like this on (I am new to the open-source community). Should I raise this as an issue on either of the devtools-protocol or PyChromeDevTools repos? Has anyone else had this behaviour with Browser.close()? Any help is much appreciated. Thanks.

François Degros

unread,
Jan 3, 2018, 11:22:04 PM1/3/18
to chrome-debugging-protocol
I noticed it as well.

Running Chrome in headless mode:

$ chrome --headless --remote-debugging-port=9222

Using chrome-remote-interface:

>>> Browser.getVersion()
...
{ protocolVersion: '1.2',
  product: 'HeadlessChrome/65.0.3311.0',
  revision: '@d1cf46fdf3acf5c7148c7a310f2095ea848405e8',
  userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/65.0.3311.0 Safari/537.36',
  jsVersion: '6.5.124' }

>>> Browser.close
{ [Function: override]
  category: 'command',
  description: 'Close browser gracefully.' }

>>> Browser.close()
...
{ Error: 'Browser.close' wasn't found
  request: { method: 'Browser.close', params: undefined },
  response: { code: -32601, message: '\'Browser.close\' wasn\'t found' } }


What does it mean? How come the Browser.close command is properly documented, but the command itself isn't defined?

Mathias Fredriksson

unread,
Jan 4, 2018, 9:35:32 AM1/4/18
to chrome-debugging-protocol
This method does not seem to be available on page targets. You should be able to use the browser target though:

$ curl -s localhost:9222/json/version | grep webSocketDebuggerUrl
   "webSocketDebuggerUrl": "ws://localhost:9222/devtools/browser/16552fae-ebec-4cf1-ab4e-0b0ca41e5427"

When connected to the this webSocketDebuggerUrl, Browser.close() should work.

I noticed another funny thing, calling Browser.close() multiple times results in the same error message (until disconnected).

SEND: {"id":8,"method":"Browser.close"}
RECV: {"id":8,"result":{}}
SEND: {"id":9,"method":"Browser.close"}
RECV: {"error":{"code":-32601,"message":"'Browser.close' wasn't found"},"id":9}
SEND: {"id":10,"method":"Browser.close"}
RECV: {"error":{"code":-32601,"message":"'Browser.close' wasn't found"},"id":10}
[disconnected]

Yves Goergen

unread,
Oct 9, 2018, 7:33:11 AM10/9/18
to chrome-debugging-protocol
Where does the "browser" URL come from? I can only see "page" WebSocket URLs in the json file. Trying to replace "page" with "browser" leads to an HTTP 404 error.

Closing Chrome doesn't seem to be possible anymore. Just kill it. Google likes that.

boris.o...@ub.io

unread,
Oct 9, 2018, 7:48:50 AM10/9/18
to chrome-debugging-protocol
For connecting to browser endpoint you can GET /json/version and read the webSocketDebuggerUrl field of the resulting JSON.

Note: browser endpoint is different from page endpoint, so you will probably need to resolve targets and attach to them to have access to "page-level" part of CDP.

Cheers,
Boris

Yves Goergen

unread,
Oct 9, 2018, 8:21:01 AM10/9/18
to chrome-debugging-protocol
Thanks, that worked. Is there a list of these URLs to fetch information from Chrome of? Now I know http://localhost:9222/json and http://localhost:9222/json/version.

boris.o...@ub.io

unread,
Oct 9, 2018, 12:50:03 PM10/9/18
to chrome-debugging-protocol
The closest thing to answering this question would be to give you the link to Chromium source mentioned in Chrome DevTools Protocol home page (https://chromedevtools.github.io/devtools-protocol/ — under "Frequently Asked Questions" > "Are the HTTP endpoints documented?"): https://cs.chromium.org/search/?q=f:devtools_http_handler.cc+%22command+%3D%3D+%22&sq=package:chromium&type=cs

So there aren't actually too many of them: version, protocol, list, new, activate and close.

Hope that helps.

Best regards,
Boris

Sarath ch

unread,
Feb 5, 2019, 4:48:41 PM2/5/19
to chrome-debugging-protocol

1) Get the driver as singleton

@Singleton
class BrowserInstance {

ChromeDriver getDriver(){
    ChromeOptions options = new ChromeOptions()
    options.addArguments("--headless --disable-gpu")
    return new ChromeDriver(options)
   }
}

2) Use Close and quit in finally block

 finally {
        chromeDriver.close()
        chromeDriver.quit()
    }

Result: you will be using only one instance at time and if you see task manager you will not find chromedriver and chrome process hanging.

Reply all
Reply to author
Forward
0 new messages