I am working on an app that involves the use of WebSockets. I have the following code as a part of the application:
io.on('connection', socket => {
let PLAYER = {};
// Listener for event 1
// Listener for event 2
// ...
socket.on('setName', ({name, role, room}) => {
PLAYER.name = name;
PLAYER.role = role;
PLAYER.room = room;
try{
joinRoom(PLAYER); // This function can throw an error
socket.emit('roomJoin');
}catch(e){
socket.emit('error', e.message);
return;
}
});
});
Now, when the joinRoom
function does throw an error, Node just crashes with the following exception:
events.js:306
throw err; // Unhandled 'error' event
^
Error [ERR_UNHANDLED_ERROR]: Unhandled error. ('error message')
The error
event is never emitted. What has made the try catch block fail?
Note: I am using TypeScript, but have removed type declarations in the above snippet as they shouldn't have anything to do with the problem.
Edit 1:
I have recreated the issue with simpler code as follows:
import express from 'express';
import socketio from 'socket.io';
import http from 'http';
const PORT = process.env.PORT || 8000;
const app = express();
const server = http.createServer(app);
const io = socketio(server);
server.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
});
const checkLength = (bar) => {
if(bar.length > 14){
throw Error('word is too long!');
}
// ...
}
io.on('connection', socket => {
console.log('new socket connection');
socket.on('foo', ({bar}) => {
try{
checkLength(bar);
}catch(e){
socket.emit('error', e.message);
return;
}
console.log('app did not crash!');
});
}
When the length of bar
is greater than 14, the app crashes with the same error mentioned above.
I am working on an app that involves the use of WebSockets. I have the following code as a part of the application:
io.on('connection', socket => {
let PLAYER = {};
// Listener for event 1
// Listener for event 2
// ...
socket.on('setName', ({name, role, room}) => {
PLAYER.name = name;
PLAYER.role = role;
PLAYER.room = room;
try{
joinRoom(PLAYER); // This function can throw an error
socket.emit('roomJoin');
}catch(e){
socket.emit('error', e.message);
return;
}
});
});
Now, when the joinRoom
function does throw an error, Node just crashes with the following exception:
events.js:306
throw err; // Unhandled 'error' event
^
Error [ERR_UNHANDLED_ERROR]: Unhandled error. ('error message')
The error
event is never emitted. What has made the try catch block fail?
Note: I am using TypeScript, but have removed type declarations in the above snippet as they shouldn't have anything to do with the problem.
Edit 1:
I have recreated the issue with simpler code as follows:
import express from 'express';
import socketio from 'socket.io';
import http from 'http';
const PORT = process.env.PORT || 8000;
const app = express();
const server = http.createServer(app);
const io = socketio(server);
server.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
});
const checkLength = (bar) => {
if(bar.length > 14){
throw Error('word is too long!');
}
// ...
}
io.on('connection', socket => {
console.log('new socket connection');
socket.on('foo', ({bar}) => {
try{
checkLength(bar);
}catch(e){
socket.emit('error', e.message);
return;
}
console.log('app did not crash!');
});
}
When the length of bar
is greater than 14, the app crashes with the same error mentioned above.
- Are you potentially missing catch statements on the .on events? I.e. io.on('connection', socket => {}).catch((err) => {}) ?. Which websocket library are you using? – Phobos Commented Sep 15, 2020 at 5:28
- @Phobos I'm using socket.io. I don't have a catch statement for the io.on('connection') event, but try-catch blocks in other events I'm listening works - just not this one, which is strange. – ml23 Commented Sep 15, 2020 at 5:36
-
1
@Phobos The
on
method doesnt have error handling on its own. What could be an issue is ifjoinRoom
is calling anasync
function that's not beingawait
-ed. If thePromise
orasync
function, errors, it cannot be caught with a reculartry-catch
block, unless anawait
is done. – Mike Commented Sep 15, 2020 at 5:36 -
I agree with @Mike,
joinRoom
is likely an async function so you need to catch the error usingjoinRoom().catchError(error => /* handle error here */)
. – bloo Commented Sep 15, 2020 at 5:50 - 1 Much much appreciated. Although, the issue was staring at us in plain sight all along. I've added my answer. – Mike Commented Sep 15, 2020 at 6:25
3 Answers
Reset to default 4After replicating the server on my local machine, I realized you were calling emit
on a reserved keyword for socket.io
. When you call socket.emit('error', e.message)
, there is an expected listener to exist. One like this:
socket.on('error', err => {
// An error occurred.
})
You should use a different phrase for your emit
. I personally use oops
on my socket servers. socket.emit('oops', {error})
. You can read more about error handling on their page.
To add, socket.emit('error')
does not pass the error or any data down to the client and instead is handled by the server, which is why you need to use a different phrase.
You can use the promisses, and than you can profite from the then() method which also returns a Promise. It takes up to two arguments: callback functions for the success and failure cases of the Promise.
So your code should be something like this:
import express from 'express';
import socketio from 'socket.io';
import http from 'http';
const PORT = process.env.PORT || 8000;
const app = express();
const server = http.createServer(app);
const io = socketio(server);
server.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
});
const checkLength = (bar) => {
return new Promise((resolve, reject)=>{
if(bar.length > 14){
// throw Error('word is too long!');
reject('word is too long!')
} else {
resolve('app did not crash!')
}
});
}
io.on('connection', socket => {
console.log('new socket connection');
socket.on('foo', ({bar}) => {
checkLength(bar).then((result) => {
console.log('app did not crash!');
}).catch(err => {
console.log("app did crash with this error:", err);
});
});
}
I noticed you hadn't initialized your PLAYER
variable.
let PLAYER = {};
#EDIT 1:
try also adding an error handler for your socket server and log it to get an idea of what is causing the error.
socket.on('error', (error) => {
console.log(error);
});