'Getting ERROR: uncaughtException: source.on is not a function, when using request and multiparty for multipart/form-data
I am trying to send data from my node application to a 3rd party HTTP endpoint.
I am parsing the data on the request object coming from the client using the multiparty module and sending the data through the request module. I am getting the error
error: uncaughtException: source.on is not a function
var request = require('request');
const multiparty = require('multiparty');
function addAttachment(req, res) {
let form = new multiparty.Form();
let parsedFile = {};
const formData = {};
form.parse(req, function(err, fields, files){
Object.keys(fields).forEach(function(name) {
formData[name] = fields[name][0];
});
Object.keys(files).forEach(function(name) {
logger.debug(name);
parsedFile[name] = files[name][0];
});
formData.uploadFile = parsedFile.uploadFile;
logger.debug('formData ', formData);
reqOptions.url = imageURL;
reqOptions.formData = formData;
logger.debug('REQ_OPTIONS ', reqOptions);
request.post(reqOptions, function (err, response, body) {
if (err) {
logger.warn(req, ' Error sending attachment', err);
res.status(400);
res.json({ "msg": "Error sending attachment" });
} else {
res.status(201);
logger.debug('BODY ', body);
res.send(body);
}
});
});
}
The reqOptions
obj contains the headers, url, auth obj, we then add the form data to it.
When I log the form data it looks to be in the correct format
{
"meta": {
"prop1": "xxxxxx",
"prop2": "xxxxxxxxxxxxx",
"uploadFile": {
"fieldName": "uploadFile",
"originalFilename": "test.PNG",
"path": "/tmp/W1IppPiK04JpkPrnZWEhzkmV.PNG",
"headers": {
"content-disposition": "form-data; name=\"uploadFile\"; filename=\"test.PNG\"",
"content-type": "image/png"
},
"size": 42786
}
}
}
Solution 1:[1]
So after some hair pulling and digging around, I was able to post form data to the external API. I decide to change the node modules I was using to connect-multiparty
. Connect will parse the request headers and decode the post-form-data allowing you to access the data from the req
obj E.G req.body
now have the added properties and req.files
has uploaded files.
const multipart = require('connect-multiparty');
const multipartMiddleware = multipart();
Then add the multipartMiddleware
to the route.
app.post('/api/addAttachment' multipartMiddleware, MyController.addAttachment);
Then in my controller file I changed the code to use connect-multipart
.
const fs = require('fs');
var request = require('request');
function addAttachment(req, res) {
const TMP = '/tmp';
let formData = {};
Object.keys(req.body).forEach((propName) =>{
if (typeof propName === 'string') {
logger.debug(propName, ' is a string');
formData[propName] = req.body[propName];
} else {
logger.debug(propName, ' is not a string')
}
});
//The files get added to the tmp folder on the files system,
//So we create a stream to read from tmp folder,
//at the end end we need to delete the file
formData['uploadFile'] = fs.createReadStream(req.files.uploadFile.path);
logger.debug('FORM DATA ', formData, '\n');
reqOptions.url = imageUrl;
reqOptions.headers = {'Content-Type': 'multipart/form-data','Accept': 'application/json'};
reqOptions.formData = formData;
logger.debug('REQ_OPTIONS ', reqOptions, '\n');
request.post(reqOptions, function (err, response, body) {
if (err) {
removeFiles(TMP);
logger.warn(req, ' Error sending attachment', err);
res.status(400);
res.json({"msg": "Error sending attachment"});
} else {
removeFiles(TMP);
res.status(201);
logger.debug('BODY ', body);
res.send(body);
}
});
}
Solution 2:[2]
This error is probably one of the best examples how error message can be perfectly misleading. Therefore. it's very frustrating to do RCA of the issue:
ERROR: uncaught Exception: source.on is not a function
Actually there is nothing about any function here. In my case, I spent hours scratching my head and finally only to find it is JSON under another JSON which was causing this error:
let subJson =
{
field1: "value1",
field2: "value2"
}
let myJson =
{
field1: "value1",
field2: "value2",
field3: subJson
}
createFormData(myJson);
This is it! When you call createFormData
with myJson
as parameter, you will see exception source.on is not a function
! And we keep thinking where is that function?
Solution is JSON.stringify
field3: JSON.stringify(subJson)
Will solve this issue.
javascript!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | DevRight |
Solution 2 | Atul |