How do I prevent my app from crashing when posting a stream to an offline destination? In both examples below I get:
internal/streams/legacy.js:59
throw er; // Unhandled stream error in pipe.
^
Error: connect ECONNREFUSED 127.0.0.1:2024
at TCPConnectWrap.afterConnect
(I'm on node v12.1.0)
import FormData from 'form-data';
import got from 'got';
import fs from 'fs';
(async () => {
try {
const form = new FormData();
form.append('upload', fs.createReadStream('filepath.jpg'));
await got.post('http://offlinesite123.com', {
body: form,
});
} catch (err) {
console.error('does not catch', err);
}
})();
this also crashes my app
try {
const form = new FormData();
form.append('upload', fs.createReadStream('filepath.jpg'));
got.stream
.post('http://offlinesite123.com', {
body: form,
})
.on('error', err => console.error('this error gets reported but app still crashes'));
} catch (err) {
console.error('does not catch', err);
}
I think we need to use Stream.pipeline here: https://github.com/sindresorhus/got/blob/master/source/request-as-event-emitter.ts#L229
I've just experienced this exact same problem, with got 9.6. Downgrading to 8.3 was a viable workaround, but obviously isn't a permanent fix.
I switched to use stream.pipeline in https://github.com/sindresorhus/got/commit/633651fb711dac21dfd573fbbd25d77968679aa3, but we still need a regression test before closing this. A PR for that would be very welcome.
Sorry, I failed to understand why is this closed? The ENOTFOUND or ECONNREFUSED errors are still not handled by catch() and crash the app when destination is offline.
This can be seen in the same snippet as above by @szmarczak (I just updated got to 11.6.0): https://runkit.com/pavek/5f56eeff9e4e8c001a3984c4
Is there a workaround that I miss in the docs?
@szmarczak Thanks for reopening. I guess it will be fixed in the next release?
I found a workaround using got streams API that, unlike promises in current version, correctly handles errors during upload. One particularly tricky part was to get response body after upload - sharing it here for it's not documented elsewhere:
const uploadFile = async (filePath, url, onProgress) => {
let error = null, json = null, response = null;
try {
const formData = new FormData();
formData.append('image', fs.createReadStream(filePath));
response = await new Promise((resolve, reject) => {
got
.post(url, {
body: formData,
isStream: true, // Use `got` streaming API as promises do not handle errors correctly in 11.6.0
})
.on('uploadProgress', onProgress)
.on('response', resolve)
.on('error', reject);
});
// Consume response body. Async Iterator works unlike `response.on('data')`
let data = '';
for await (const chunk of response) {
data += chunk;
}
json = JSON.parse(data);
}
catch (e) {
error = e;
}
return { error, json, response };
};
This is possibly a Node.js bug. Investigating more.
@szmarczak are there any updates on this one?
It's fixed via a Node.js update. Just checked the latest one, works as expected.
Most helpful comment
I switched to use
stream.pipelinein https://github.com/sindresorhus/got/commit/633651fb711dac21dfd573fbbd25d77968679aa3, but we still need a regression test before closing this. A PR for that would be very welcome.