Closed brandonros closed 6 years ago
@brandonros I'm suspecting it has to do with the first-class IPv6 support Node v4 has. cc @mscdex maybe.
Edit: added IPv6
What OS and OS version is this on?
@mscdex
Linux Nigel 3.13.0-43-generic #72-Ubuntu SMP Mon Dec 8 19:35:44 UTC 2014 i686 i686 i686 GNU/Linux
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.3 LTS
Release: 14.04
Codename: trusty
@Fishrock123 @mscdex Any other information I can provide? Would love to get this fixed quickly. I'm sure it has to be something on my end, otherwise a huge portion of people would be experiencing it.
The code used to work without issue, but it started happening a) when I changed machines and b) when I switched versions.
I installed with nvm if that matters.
Is it happening with the same server(s)? If so, are these public servers? Otherwise, if you can, it might be helpful to see what types of addresses the servers are resolving to (e.g. IPv4, IPv6) and what types of addresses are assigned to the outgoing network interface the requests are going out.
@mscdex It is happening on the same offending server. It seems to happen on both requests made to localhost, and external APIs. All IPv4.
Also encountered on OS X (My computer) and Ubuntu (Travis-CI) and Windows Server (AppVeyor) when using npm package 'request', the error trace is exactly same as described by @brandonros
It sounds like you are trying to use port 80 for https?
Reproduced via:
require('https').get('https://google.com:80', function(res) { console.log(res.statusCode) }).on('error', console.log)
The reason that isn't the problem in my case is because it only happens semi-frequently on otherwise valid endpoints.
On Sunday, November 8, 2015, Evan Lucas notifications@github.com wrote:
It sounds like you are trying to use port 80 for https?
Reproduced via:
require('https').get('https://google.com:80', function(res) { console.log(res.statusCode) }).on('error', console.log)
— Reply to this email directly or view it on GitHub https://github.com/nodejs/node/issues/3692#issuecomment-154899692.
It will be difficult for us to help debug the issue without being able to see some of the code. Is there any that you could share?
I went to dumb down some code I have, and it really just boils down to any HTTP or HTTPS request. Nothing else.
@trotyl Do you think it has anything to do with DNS or nginx rewrites? I'm really stretching here. I can't come up with anything else.
It appears on some certain urls and randomly, I cannot even cause it to appear manually, and I have used a 'retry(100)' of RxJS to get rid of this problem. But it seems not a good solution.
Some url(s) on my crawler of my university site may cause the problem at some low possibility, I do have no idea where it came from as error trace directly begin from 'net.js', But what I can guess seems to be DNS or HTTPS or something relevant.
The url I have problem with seems to be 'https://uis.uestc.edu.cn/amserver/UI/Login' with method 'POST' with form 'IDToken0&IDToken=2012019050020&IDToken2=811073&IDButton=Submit&goto=aHR0cDovL3BvcnRhbC51ZXN0Yy5lZHUuY24vbG9naW4ucG9ydGFs&encoded=true&gx_charset=UTF-8', (the id and password is not mine but valid)
Upgrading to 5.0, changing machines, and switching to 64-bit seems to have fixed the problem. I don't want to jinx anything, but I have not seen the error in 3 days.
The error is still happening. I am installing longjohn on all of my servers to get more information.
@trotyl Any update?
How is this for a stack trace?
Error: write EPROTO
at Object.exports._errnoException (util.js:860:11)
at exports._exceptionWithHostPort (util.js:883:20)
at WriteWrap.afterWrite (net.js:763:14)
---------------------------------------------
at TLSSocket.Readable.on (_stream_readable.js:665:33)
at tickOnSocket (_http_client.js:486:10)
at onSocketNT (_http_client.js:502:5)
at doNTCallback2 (node.js:450:9)
at process._tickDomainCallback (node.js:405:17)
---------------------------------------------
at ClientRequest.onSocket (_http_client.js:494:11)
at Agent.addRequest (_http_agent.js:143:9)
at new ClientRequest (_http_client.js:139:16)
at Object.exports.request (http.js:31:10)
at Object.exports.request (https.js:173:15)
at Object.ebay.request (/home/brandon/foo/integrations/ebay.js:34:18)
at Object.ebay.get_orders_api_call (/home/brandon/foo/integrations/ebay.js:122:7)
at Object.ebay.get_orders (/home/brandon/foo/integrations/ebay.js:138:7)
at handle_job (/home/brandon/foo/sync_server/app.js:124:29)
at /home/brandon/foo/sync_server/app.js:214:12
at process._tickDomainCallback (node.js:420:9)
at /home/brandon/foo/api_server/lib/sync_server.js:77:11
at _fulfilled (/home/brandon/foo/api_server/node_modules/q/q.js:834:54)
at self.promiseDispatch.done (/home/brandon/foo/api_server/node_modules/q/q.js:863:30)
at Promise.promise.promiseDispatch (/home/brandon/foo/api_server/node_modules/q/q.js:796:13)
at /home/brandon/foo/api_server/node_modules/q/q.js:604:44
at runSingle (/home/brandon/foo/api_server/node_modules/q/q.js:137:13)
at flush (/home/brandon/foo/api_server/node_modules/q/q.js:125:13)
at doNTCallback0 (node.js:428:9)
at process._tickDomainCallback (node.js:398:13)
---------------------------------------------
at requestTick (/home/brandon/foo/api_server/node_modules/q/q.js:197:21)
at Function.nextTick (/home/brandon/foo/api_server/node_modules/q/q.js:180:13)
at /home/brandon/foo/api_server/node_modules/q/q.js:603:15
at Array.reduce (native)
at /home/brandon/foo/api_server/node_modules/q/q.js:263:21
at become (/home/brandon/foo/api_server/node_modules/q/q.js:602:9)
at deferred.resolve (/home/brandon/foo/api_server/node_modules/q/q.js:618:9)
at IncomingMessage.<anonymous> (/home/brandon/foo/api_server/lib/sync_server.js:17:13)
at emitNone (events.js:72:20)
at IncomingMessage.emit (events.js:166:7)
at endReadableNT (_stream_readable.js:905:12)
at doNTCallback2 (node.js:450:9)
at process._tickDomainCallback (node.js:405:17)
---------------------------------------------
at IncomingMessage.Readable.on (_stream_readable.js:665:33)
at Object.sync_server.read_body (/home/brandon/foo/api_server/lib/sync_server.js:15:11)
at ClientRequest.<anonymous> (/home/brandon/foo/api_server/lib/sync_server.js:45:22)
at emitOne (events.js:77:13)
at ClientRequest.emit (events.js:169:7)
at HTTPParser.parserOnIncomingClient (_http_client.js:421:21)
at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)
at Socket.socketOnData (_http_client.js:311:20)
at emitOne (events.js:77:13)
at Socket.emit (events.js:169:7)
at readableAddChunk (_stream_readable.js:146:16)
at Socket.Readable.push (_stream_readable.js:110:10)
at TCP.onread (net.js:523:20)
---------------------------------------------
at Object.sync_server.request (/home/brandon/foo/api_server/lib/sync_server.js:44:6)
at /home/brandon/foo/api_server/lib/sync_server.js:73:23
at _fulfilled (/home/brandon/foo/api_server/node_modules/q/q.js:834:54)
at self.promiseDispatch.done (/home/brandon/foo/api_server/node_modules/q/q.js:863:30)
at Promise.promise.promiseDispatch (/home/brandon/foo/api_server/node_modules/q/q.js:796:13)
at /home/brandon/foo/api_server/node_modules/q/q.js:604:44
at runSingle (/home/brandon/foo/api_server/node_modules/q/q.js:137:13)
at flush (/home/brandon/foo/api_server/node_modules/q/q.js:125:13)
at doNTCallback0 (node.js:428:9)
at process._tickDomainCallback (node.js:398:13)
---------------------------------------------
at requestTick (/home/brandon/foo/api_server/node_modules/q/q.js:197:21)
at Function.nextTick (/home/brandon/foo/api_server/node_modules/q/q.js:180:13)
at /home/brandon/foo/api_server/node_modules/q/q.js:603:15
at Array.reduce (native)
at /home/brandon/foo/api_server/node_modules/q/q.js:263:21
at become (/home/brandon/foo/api_server/node_modules/q/q.js:602:9)
at deferred.resolve (/home/brandon/foo/api_server/node_modules/q/q.js:618:9)
at [object Object].<anonymous> (/home/brandon/foo/api_server/node_modules/q/q.js:1859:22)
at Timer.listOnTimeout (timers.js:92:15)
---------------------------------------------
at /home/brandon/foo/api_server/node_modules/q/q.js:1858:9
at _fulfilled (/home/brandon/foo/api_server/node_modules/q/q.js:834:54)
at self.promiseDispatch.done (/home/brandon/foo/api_server/node_modules/q/q.js:863:30)
at Promise.promise.promiseDispatch (/home/brandon/foo/api_server/node_modules/q/q.js:796:13)
at /home/brandon/foo/api_server/node_modules/q/q.js:857:14
at runSingle (/home/brandon/foo/api_server/node_modules/q/q.js:137:13)
at flush (/home/brandon/foo/api_server/node_modules/q/q.js:125:13)
at doNTCallback0 (node.js:428:9)
at process._tickDomainCallback (node.js:398:13)
---------------------------------------------
at requestTick (/home/brandon/foo/api_server/node_modules/q/q.js:197:21)
at Function.nextTick (/home/brandon/foo/api_server/node_modules/q/q.js:180:13)
at /home/brandon/foo/api_server/node_modules/q/q.js:603:15
at Array.reduce (native)
at /home/brandon/foo/api_server/node_modules/q/q.js:263:21
at become (/home/brandon/foo/api_server/node_modules/q/q.js:602:9)
at deferred.resolve (/home/brandon/foo/api_server/node_modules/q/q.js:618:9)
at IncomingMessage.<anonymous> (/home/brandon/foo/api_server/lib/sync_server.js:17:13)
at emitNone (events.js:72:20)
at IncomingMessage.emit (events.js:166:7)
at endReadableNT (_stream_readable.js:905:12)
at doNTCallback2 (node.js:450:9)
at process._tickDomainCallback (node.js:405:17)
---------------------------------------------
at IncomingMessage.Readable.on (_stream_readable.js:665:33)
at Object.sync_server.read_body (/home/brandon/foo/api_server/lib/sync_server.js:15:11)
at ClientRequest.<anonymous> (/home/brandon/foo/api_server/lib/sync_server.js:45:22)
at emitOne (events.js:77:13)
at ClientRequest.emit (events.js:169:7)
at HTTPParser.parserOnIncomingClient (_http_client.js:421:21)
at HTTPParser.parserOnHeadersComplete (_http_common.js:88:23)
at Socket.socketOnData (_http_client.js:311:20)
at emitOne (events.js:77:13)
at Socket.emit (events.js:169:7)
at readableAddChunk (_stream_readable.js:146:16)
at Socket.Readable.push (_stream_readable.js:110:10)
at TCP.onread (net.js:523:20)
---------------------------------------------
at Object.sync_server.request (/home/brandon/foo/api_server/lib/sync_server.js:44:6)
at Object.sync_server.request_refresh (/home/brandon/foo/api_server/lib/sync_server.js:99:21)
at /home/brandon/foo/api_server/controllers/sync.js:131:22
at _fulfilled (/home/brandon/foo/api_server/node_modules/q/q.js:834:54)
at self.promiseDispatch.done (/home/brandon/foo/api_server/node_modules/q/q.js:863:30)
at Promise.promise.promiseDispatch (/home/brandon/foo/api_server/node_modules/q/q.js:796:13)
at /home/brandon/foo/api_server/node_modules/q/q.js:604:44
at runSingle (/home/brandon/foo/api_server/node_modules/q/q.js:137:13)
at flush (/home/brandon/foo/api_server/node_modules/q/q.js:125:13)
at doNTCallback0 (node.js:428:9)
at process._tickDomainCallback (node.js:398:13)
---------------------------------------------
at requestTick (/home/brandon/foo/api_server/node_modules/q/q.js:197:21)
at Function.nextTick (/home/brandon/foo/api_server/node_modules/q/q.js:180:13)
at /home/brandon/foo/api_server/node_modules/q/q.js:603:15
at Array.reduce (native)
at /home/brandon/foo/api_server/node_modules/q/q.js:263:21
at become (/home/brandon/foo/api_server/node_modules/q/q.js:602:9)
at deferred.resolve (/home/brandon/foo/api_server/node_modules/q/q.js:618:9)
at _fulfilled (/home/brandon/foo/lib/node_modules/q/q.js:834:54)
at self.promiseDispatch.done (/home/brandon/foo/lib/node_modules/q/q.js:863:30)
at Promise.promise.promiseDispatch (/home/brandon/foo/lib/node_modules/q/q.js:796:13)
at /home/brandon/foo/lib/node_modules/q/q.js:604:44
at runSingle (/home/brandon/foo/lib/node_modules/q/q.js:137:13)
at flush (/home/brandon/foo/lib/node_modules/q/q.js:125:13)
at doNTCallback0 (node.js:428:9)
at process._tickDomainCallback (node.js:398:13)
I had
var headers = {
...
'Content-Type': 'text/xml',
'Content-Length': Buffer(body).byteLength
};
But I think this was the culpritL
var headers = {
...
'Content-Type': 'text/xml',
'Content-Length': body.length
};
I'm also receiving this error intermittently on random servers and URLs (though all are being accessed via HTTPS). @brandonros - Based on other threads, I'm investigating the possibility of this being caused by drop of RC4 support in Node >= v4.0. Any update on your end?
@BennyH26 Say this is the case. What can be done to fix this?
Edit: Maybe the reason this is happening intermittently is because we are getting load balanced to different servers?
I'm going to test if these options will fix the problem. I'm not sure if they are correct.
var options = {
...
ciphers: 'ALL',
secureProtocol: 'TLSv1_method'
};
/cc @nodejs/http
@brandonros I've added the code to my agent options, and will keep you posted if I still receive errors. Intermittent errors are so challenging to solve sometimes... As you suggested, I suspect we are hitting load balanced servers, and their reverse proxy configurations are SLIGHTLY different, thereby negotiating different ciphers. Just a guess though.
@BennyH26 What servers/URLs are you hitting? I ran eBay's API endpoint through https://www.ssllabs.com/ssltest/, if that helps.
@brandonros https://api.ebay.com/ws/api.dll Looks like two of the three servers got C grades =]
@trotyl are you sure about OS X? This seems pretty strange to me, because I don't see a place in kernel that could set errno = EPROTO for TCP syscalls.
Gosh, nevermind. It is returned by src/tls_wrap.cc
, not kernel. My bad!
This is very likely happened, because there were pending writes on TLS socket and it was destroyed before they were encrypted and sent to the other side.
I think this kind of error can only happen if ssl_ == nullptr
in TLSWrap::DoWrite
.
@brandonros may I ask you to give a try to following patch?
diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js
index ef5769c..d517d1b 100644
--- a/lib/_tls_wrap.js
+++ b/lib/_tls_wrap.js
@@ -47,7 +47,11 @@ function onhandshakestart() {
function onhandshakedone() {
// for future use
debug('onhandshakedone');
- this._finishInit();
+
+ const self = this;
+ setImmediate(function() {
+ self._finishInit();
+ });
}
@@ -556,6 +560,10 @@ TLSSocket.prototype._releaseControl = function() {
};
TLSSocket.prototype._finishInit = function() {
+ // Destroyed before getting there
+ if (this._handle == null)
+ return;
+
// `newSession` callback wasn't called yet
if (this._newSessionPending) {
this._securePending = true;
Basically, what I think happens here is that ssl_
is destroyed in the middle of DoWrite
. Otherwise I can't see how it could happen. I'm trying to make sure that no unsafe JS callbacks will be executed from within DoWrite
.
(It doesn't seem like it could be any other UV_EPROTO case from tls_wrap.cc
, because the error would include some OpenSSL strings as well in that case)
@indutny Do you think the options I pass as per https://github.com/nodejs/node/issues/3692#issuecomment-158414743 will interfere or solve the issue?
I will try the patch but the error very rarely happens. I guess I could write a test to try to exacerbate the behavior.
@brandonros this sounds unlikely.
@indutny what drastic breaking changes occurred here from 0.12.7 to 4.0.0 and so on? Default ciphers supported? Some overhauling?
This issue did not exist in 0.12.7
@brandonros there were tons of changes in TLS implementation.
+1 We also faced this issue (Error: write EPROTO after https requests) on production servers after migrating to node.js v5.0.0 from 1.8.4 This error seems to happen occasionally (maybe 1 time in 20) and we can't find the reason.
We're also seeing this issue when trying to connect to https://api2.dynect.net/ with Node 4.2.x.
The example below uses request but the same issue happens with the https client. About 50% of the time this will return a EPROTO error.
var request = require("request")
request('https://api2.dynect.net/', function(error, res, body)
{
console.log(error, body)
});
Just for information - we fixed this issue. But we fixed it by changing nginx cyphers config at our API backend. We used this recommendations by mozilla (orange level was enough for us): https://wiki.mozilla.org/Security/Server_Side_TLS So now we have production environment on Node.js 5.0.0. working without any errors.
@aclelland Unfortunately I'm unable to reproduce this problem locally with your script. May I ask you to give a try to the patch that I have posted earlier in this thread: https://github.com/nodejs/node/issues/3692#issuecomment-158583358 ?
@SanchesS @aclelland btw, could you please paste the stack trace of the EPROTO
error?
@indutny sorry, but we don't have full stack trace - currently bug is fixed and we cannot reproduce it on test servers. This is all that we got:
code: 'EPROTO',
errno: 'EPROTO',
syscall: 'write',
address: undefined }
Error: write EPROTO
I am getting this intermittent error as well (node 5.0.0). The stack trace I get is:
Error: write EPROTO
at Object.exports._errnoException (util.js:860:11)
at exports._exceptionWithHostPort (util.js:883:20)
at WriteWrap.afterWrite (net.js:763:14)
That error suggests the TLS handshake failed and the remote end closed the connection with prejudice. Nine times out of ten it means the server and the client couldn't agree on a cipher to use. Poke around with openssl s_client
and see what works and what doesn't.
Same problem on node 5.0.0, callstack looks the same to @brandonros post. Happens pretty randomly, but when it does, there are few errors in row (can return errors for all requests for a minute once in a day). Did anyone catching the error on node 5.3.0? UPD: We are using EC2 and this error occurs only on the same instances. For example: on two cluster with three instances each, only one instance in each cluster produces the bug.
May I ask you to give a try to https://github.com/nodejs/node/pull/4515 to see if it helps?
I've moved to 5.2.0 and all my problems have dissapeared.
Interesting... Looks like it can be a manifestation of https://github.com/nodejs/node/commit/939f305d567c927c7e6ab551529984cec3b68479 . Everyone here, please give a try to v5.2.0 and confirm it if you'll have time for this.
Thank you!
Having the same issue here when I try to use a proxy. I tested in version 4.2.4, 4.2.1, 5.2.0 and 5.4.0.
const request = require('request');
let r = request.defaults({'proxy': 'https://81.94.162.140:8080/'});
r.get('http://www.example.com/', (error, response) => {
if (error) {
return console.log(error.stack);
}
console.log(response.body);
});
Error: write EPROTO at Object.exports._errnoException (util.js:856:11) at exports._exceptionWithHostPort (util.js:879:20) at WriteWrap.afterWrite (net.js:764:14)
I'm running a server using on port 80 using HTTP and see the error occasionally on Node 4.2.1 when developing locally. I just got the same error on a staging server (also HTTP, port 80) running 5.0.0 which makes me think this doesn't have much to do with TLS. (Unless it's a similar symptom of a different problem.)
Ah, sorry. Just had a look at the stack trace and it's to do with accessing dynamodb over HTTPS. So ignore my previous comment!
I have noticed it's happening more often now, which could just be because I'm hitting the database more frequently.
I've also been hitting this problem repeatedly for the past two weeks while writing to/reading from DynamoDB on Node v5.2.0. The stack trace is the same as some people here have mentioned:
Error: write EPROTO
at Object.exports._errnoException (util.js:856:11)
at exports._exceptionWithHostPort (util.js:879:20)
at WriteWrap.afterWrite (net.js:764:14)
If I can be of any help, please let me know.
I got this
{ [Error: write EPROTO 140735221207808:error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol:../deps/openssl/openssl/ssl/s23_clnt.c:795:
] code: 'EPROTO', errno: 'EPROTO', syscall: 'write' }
the problem was targeting the wrong port
I am also getting same error consistently for one API call. I am trying to call 4 different APIs - one is just http and three are https via request (https://www.npmjs.com/package/request) and its working fine for http and two https cases. But always failing for one case.
My code is littered with both HTTP and HTTPS requests. I have no idea what is causing this error but it is occurring in many places since I've upgraded to 4.2.1 from 0.12.7. Please tell me what information I need to provide to help debug this.