diff --git a/lib/net.js b/lib/net.js index 25767b25741644..ba7c3eb6daca0d 100644 --- a/lib/net.js +++ b/lib/net.js @@ -401,8 +401,7 @@ function writeAfterFIN(chunk, encoding, cb) { // eslint-disable-next-line no-restricted-syntax var er = new Error('This socket has been ended by the other party'); er.code = 'EPIPE'; - // TODO: defer error events consistently everywhere, not just the cb - this.emit('error', er); + process.nextTick(emitErrorNT, this, er); if (typeof cb === 'function') { defaultTriggerAsyncIdScope(this[async_id_symbol], process.nextTick, cb, er); } diff --git a/test/parallel/test-net-write-after-end-nt.js b/test/parallel/test-net-write-after-end-nt.js new file mode 100644 index 00000000000000..3f93b444f4cb36 --- /dev/null +++ b/test/parallel/test-net-write-after-end-nt.js @@ -0,0 +1,26 @@ +'use strict'; +const common = require('../common'); + +const assert = require('assert'); +const net = require('net'); + +const { mustCall } = common; + +// This test ensures those errors caused by calling `net.Socket.write()` +// after sockets ending will be emitted in the next tick. +const server = net.createServer(mustCall((socket) => { + socket.end(); +})).listen(() => { + const client = net.connect(server.address().port, () => { + let hasError = false; + client.on('error', mustCall((err) => { + hasError = true; + server.close(); + })); + client.on('end', mustCall(() => { + client.write('hello', mustCall()); + assert(!hasError, 'The error should be emitted in the next tick.'); + })); + client.end(); + }); +});