70

My socket currently throws net::ERR_CONNECTION_REFUSED because the server isn't running, which I want it to do at the moment.

The problem is that the following piece of code doesn't catch the error. In the console, I see an exception on line 2 (with net::ERR_CONNECTION_REFUSED) which I believe shouldn't happen as it's within a try statement.

try {
  ws = new WebSocket('ws://'+ host + ':' + port + '/');
}
catch (err) {
  console.log('This never prints');
}
ws.onerror = function (error) {
  console.log(error);
};

So my question is why is it not being caught?

What I ultimately want is for the error message to be displayed elsewhere, but I can't catch it, and line 8 prints an "event" object which doesn't mention net::ERR_CONNECTION_REFUSED, so I'm not sure how to get the error message out.

1
  • 2
    Great question. Same issue here. Commented Jun 27, 2021 at 11:41

4 Answers 4

128

The WebSocket's connection-time error causes a dispatched event, not a thrown value. This is because throw operations must be synchronous. In order to handle all connection-time errors as thrown errors, the WebSocket constructor would need to completely suspend all script execution and UI interaction until the entire WebSocket handshake had completed. Instead, the connection process runs asynchronously, thereby allowing the browser thread to continue working while the WebSocket connection initializes in the background. Because of the connection's asynchronous nature, the WebSocket must report errors via error events, since the synchronous new WebSocket operation has already finished by the time the asynchronous connection task encounters an error.

The ERR_CONNECTION_REFUSED message you see is purely for the benefit of developers; it is not accessible to the script in any way. It does not have any representation within the JavaScript environment. It's just a red-colored message that appears in your console to inform you, the human looking at the browser, about an error.

The error handler event is the correct place to respond to failure, but the lack of script-readable connection-time error information is by design. From the WHATWG spec for the WebSocket API:

User agents must not convey any failure information to scripts in a way that would allow a script to distinguish the following situations:

  • A server whose host name could not be resolved.
  • A server to which packets could not successfully be routed.
  • A server that refused the connection on the specified port.
  • A server that failed to correctly perform a TLS handshake (e.g., the server certificate can't be verified).
  • A server that did not complete the opening handshake (e.g. because it was not a WebSocket server).
  • A WebSocket server that sent a correct opening handshake, but that specified options that caused the client to drop the connection (e.g. the server specified a subprotocol that the client did not offer).
  • A WebSocket server that abruptly closed the connection after successfully completing the opening handshake.

[...] Allowing a script to distinguish these cases would allow a script to probe the user's local network in preparation for an attack.

The browser is deliberately omitting any useful information as required by the spec. The spec authors are concerned that access to this information could allow a malicious Web page to gain information about your network, so they require browsers report all connection-time errors in an indistinguishable way.

Sign up to request clarification or add additional context in comments.

16 Comments

That is very helpful information, though I don't see why the exception is not "caught". That seems to break the fundamental framework of the language. I presume that the way to do what I want would be to handle onclose and look at the CloseEvent's code.
@AndyHasIt I added an opening paragraph about that; I hope it's clear enough. Basically, we can't catch an error because we synchronously exit the try block before the the asynchronous connection attempt encounters an error.
How can I prevent the error from showing up in console though? none of ws.onerror = ev => { ev.stopImmediatePropagation() ev.stopPropagation() ev.preventDefault() return false } helps at all.
@OuuGiii You could do with with a Promise catch approach, but the WebSocket API is not Promise-aware, so you need to make your own Promise objects. See this fiddle I just made. You still have to listen for the error-event and call reject to make any catch mechanics trigger. You can't even throw because the onerror resolution is happening chronologically outside the new Promise function. Again, all a WebSocket constructor does on connection-failure is dispatch an event that happens to be named error; it doesn't raise an exception.
This is not good. My web client polls not running server each 1 second and writes each time to the console log this error.
|
-1

I tried creating fiddle with it and I am able to see line printed.

host='localhost';
port=100;
try {

    ws = new WebSocket('ws://'+ host + ':' + port + '/');
  }
  catch (err) {
    console.log('This never prints');
  }
  ws.onerror = function (error) {
    console.log(error);
  };

https://jsfiddle.net/xzumgag0/

2 Comments

That's due to a different error, though: "An insecure WebSocket connection may not be initiated from a page loaded over HTTPS."
Indeed, the jsfiddle example catches the error, but if you open your console and run the same it doesn't catch the error. As dfreeman points out these are different errors.
-1
        try{        
            socket = new WebSocket('wss://hh:4430');
        }catch(err){
            //you cannot catch new WebSocket
        }
        
        setTimeout(function(){
            //console.log(socket);
            if(typeof socket=='object' && socket.readyState==3){//could not be opened
                alert('WebSocket Not Opened');
            }
        },1200);//desired time to be wait to check websocket

https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState

Comments

-2

You can get the error in the onclose method;

var websockets =  new WebSocket('ws://127.0.0.1:9999/websocket');
var isOpen = false;
websockets.onopen = (event) => {
  isOpen = true;
};
websockets.onclose = (event) => {
  console.log(event)
  if (!isOpen) {
    // get the error
  }
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.