Heroku PDFTK throwing vague EPIPE and EACCES error - node.js

I have an app on a heroku hobby web dyno running a fairly basic node api.
We have a series of pdf's that get attached to a pdf generated by puppeteer.
My code works when I run it locally (windows) but it also works when I deploy to a my production heroku instance.
Here's the problematic code:
try{
//If there are pdfs to attach to the end of the file, we do it here.
let fileList = [];
console.log('*');
for (const file of pdfFileNameList) {
fileList.push("./pdfs/" + file.pdf);
}
console.log('**');
//Spawn a child process to run pdftk to merge the pdfs.
let execer = require('child_process').spawn;
let child;
let args = ['-'].concat(fileList).concat(['cat', 'output', '-']);
console.log(args);
console.log('***');
child = execer('pdftk', args, {
encoding: 'binary',
stdio: ['pipe']
});
//Write the file PDF binary data to the child process' stdin.
//It will combine that with the list of pdfs specified in fileList.
console.log('****');
child.stdin.write(data);
console.log('*****');
child.stdin.end();
console.log('******');
let bufferArray = [];
//shove the data from the child process into my bufferArray as it comes in.
child.stdout.on('data', function (pdfdata) {
bufferArray.push(new Buffer(pdfdata, 'binary'));
});
console.log('*******');
//When the process is done, send the concatted pdf to the user.
child.on('close', function () {
res.header('Content-Type', "application/pdf");
res.send(Buffer.concat(bufferArray));
});
console.log('********');
} catch (err) {
console.error(err);
}
And here's the resulting set of errors:
2020-01-16T18:02:37.830775+00:00 app[web.1]: *
2020-01-16T18:02:38.356266+00:00 app[web.1]: **
2020-01-16T18:02:38.358310+00:00 app[web.1]: [ '-', '/app/pdfs/Example.pdf', 'cat', 'output', '-' ]
2020-01-16T18:02:38.358371+00:00 app[web.1]: ***
2020-01-16T18:02:38.373374+00:00 app[web.1]: ****
2020-01-16T18:02:38.375832+00:00 app[web.1]: Error: write EPIPE
2020-01-16T18:02:38.375836+00:00 app[web.1]: at afterWriteDispatched (internal/stream_base_commons.js:149:25)
2020-01-16T18:02:38.375838+00:00 app[web.1]: at writeGeneric (internal/stream_base_commons.js:140:3)
2020-01-16T18:02:38.375843+00:00 app[web.1]: at Socket._writeGeneric (net.js:776:11)
2020-01-16T18:02:38.375845+00:00 app[web.1]: at Socket._write (net.js:788:8)
2020-01-16T18:02:38.375847+00:00 app[web.1]: at doWrite (_stream_writable.js:435:12)
2020-01-16T18:02:38.375849+00:00 app[web.1]: at writeOrBuffer (_stream_writable.js:419:5)
2020-01-16T18:02:38.375851+00:00 app[web.1]: at Socket.Writable.write (_stream_writable.js:309:11)
2020-01-16T18:02:38.375853+00:00 app[web.1]: at Object.returnReport (/app/models/report_functions.js:245:33) {
2020-01-16T18:02:38.375855+00:00 app[web.1]: errno: 'EPIPE',
2020-01-16T18:02:38.375857+00:00 app[web.1]: code: 'EPIPE',
2020-01-16T18:02:38.375859+00:00 app[web.1]: syscall: 'write'
2020-01-16T18:02:38.375861+00:00 app[web.1]: }
2020-01-16T18:02:38.378481+00:00 app[web.1]: events.js:200
2020-01-16T18:02:38.378484+00:00 app[web.1]: throw er; // Unhandled 'error' event
2020-01-16T18:02:38.378486+00:00 app[web.1]: ^
2020-01-16T18:02:38.378488+00:00 app[web.1]:
2020-01-16T18:02:38.378490+00:00 app[web.1]: Error: spawn pdftk EACCES
2020-01-16T18:02:38.378492+00:00 app[web.1]: at Process.ChildProcess._handle.onexit (internal/child_process.js:264:19)
2020-01-16T18:02:38.378495+00:00 app[web.1]: at onErrorNT (internal/child_process.js:456:16)
2020-01-16T18:02:38.378497+00:00 app[web.1]: at processTicksAndRejections (internal/process/task_queues.js:81:21)
2020-01-16T18:02:38.378499+00:00 app[web.1]: Emitted 'error' event on ChildProcess instance at:
2020-01-16T18:02:38.378501+00:00 app[web.1]: at Process.ChildProcess._handle.onexit (internal/child_process.js:270:12)
2020-01-16T18:02:38.378503+00:00 app[web.1]: at onErrorNT (internal/child_process.js:456:16)
2020-01-16T18:02:38.378505+00:00 app[web.1]: at processTicksAndRejections (internal/process/task_queues.js:81:21) {
2020-01-16T18:02:38.378507+00:00 app[web.1]: errno: 'EACCES',
2020-01-16T18:02:38.378509+00:00 app[web.1]: code: 'EACCES',
2020-01-16T18:02:38.378511+00:00 app[web.1]: syscall: 'spawn pdftk',
2020-01-16T18:02:38.378513+00:00 app[web.1]: path: 'pdftk',
2020-01-16T18:02:38.378515+00:00 app[web.1]: spawnargs: [ '-', '/app/pdfs/Example.pdf', 'cat', 'output', '-' ]
2020-01-16T18:02:38.378517+00:00 app[web.1]: }

In case anyone else comes across this error "Error: spawn pdftk ENOENT".
This error is most probably because Heroku can't find 'PdfTK' on your system.
Adding this buildpack to Heroku solved it for me:
'https://github.com/fxtentacle/heroku-pdftk-buildpack.git'
(I added it under the 'heroku/nodejs' buldback)

Related

Node Server ECONNRESET error occurs after running a sql request

I'm making a node server using socket.js and a MYSQL DB,
socket.on("signUp", (userSignUp) => {
console.log(userSignUp);
con.connect(function() {
con.query("SELECT COUNT(*) AS count FROM users WHERE username = '" + userSignUp.username + "'", function (err, result, fields) {
console.log(result[0].count);
if (result[0].count >= 1) {
socket.emit("signUpError", 'user-allready-exists');
return;
}
});
});
});
When I run this function, it successfully gets the data from the db however after aproximatly 30 seconds, it gives me this error>>>
Error: read ECONNRESET
at TCP.onStreamRead (node:internal/stream_base_commons:217:20)
Emitted 'error' event on Connection instance at:
at Connection._handleProtocolError (D:\Projects\server\node_modules\mysql\lib\Connection.js:423:8)
at Protocol.emit (node:events:513:28)
at Protocol._delegateError (D:\Projects\server\node_modules\mysql\lib\protocol\Protocol.js:398:10)
at Protocol.handleNetworkError (D:\Projects\server\node_modules\mysql\lib\protocol\Protocol.js:371:10)
at Connection._handleNetworkError (D:\Projects\server\node_modules\mysql\lib\Connection.js:418:18)
at Socket.emit (node:events:513:28)
at emitErrorNT (node:internal/streams/destroy:151:8)
at emitErrorCloseNT (node:internal/streams/destroy:116:3)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
errno: -4077,
code: 'ECONNRESET',
syscall: 'read',
fatal: true
}
I have had a good look around, but i can't seem to find what is causing this issue. Any help would be greatly appreciated.

spawn cd ENOENT

I am building a command line package.
I am using the spawn method to execute cd command.
Here's the code:
const cdChild = spawn('cd', [projectName])
cdChild.stdout.on('data', (data) => {
console.log(data.toString())
})
cdChild.on('error', (err) => {
console.log(err)
})
It gives the following error:
Error: spawn cd ENOENT
at Process.ChildProcess._handle.onexit (node:internal/child_process:282:19)
at onErrorNT (node:internal/child_process:477:16)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
errno: -4058,
code: 'ENOENT',
syscall: 'spawn cd',
path: 'cd',
spawnargs: [ 'bruh' ]
}
OS: Windows 10 21H1
Node: v16.13.0

imageMagick fails at socket instance

I'm using the imageMagick subclass of graphicsmagick to alter ~7k png images. The function below gets about 2/3 of the way through and fails (see log).
Seems to be an issue where a socket is failing. How do I debug this?
A thought I have is to use the -limit method, but no dice...
Thanks in advance :)
Code:
// changing an image's resolution is the same thing as changing its DPI
export default async function changeScreenshotResolution(dimension) {
new Promise(() => {
try {
const screenshots = fs.readdirSync(path.join(__dirname, `../output/screenshots/${dimension}`), function(error) {if (error) console.log(error)});
screenshots.map(screenshot => {
try {
let readStream = fs.createReadStream(path.join(__dirname, `../output/screenshots/${dimension}/${screenshot}`));
let writeStream = fs.createWriteStream(path.join(__dirname, `../output/screenshots/${dimension}1/${screenshot}`));
im(readStream, screenshot)
.limit('memory', '32MB') // i tried variations of this but it made no difference
.units('PixelsPerInch')
.density(300,300)
.stream()
.pipe(writeStream)
console.log(screenshot);
} catch (error) {
console.log(`Error changing screenshot resolution: ${error}`);
}
})
} catch (error) {
console.log(`changeScreenshotResolution error: ${error}`);
}
})
};
Error: spawn convert EAGAIN
at Process.ChildProcess._handle.onexit (internal/child_process.js:268:19)
at onErrorNT (internal/child_process.js:468:16)
at processTicksAndRejections (internal/process/task_queues.js:84:21) {
errno: -35,
code: 'EAGAIN',
syscall: 'spawn convert',
path: 'convert',
spawnargs: [
'-density',
'300x300',
'/Users/daddy/Dev/scout/project-sunroof-scraping/output/screenshots/rect/6550 ARABIAN CIR.png',
'-units',
'PixelsPerInch',
'/Users/daddy/Dev/scout/project-sunroof-scraping/output/screenshots/rect1/6550 ARABIAN CIR.png'
]
}
events.js:292
throw er; // Unhandled 'error' event
^
Error: read ENOTCONN
at tryReadStart (net.js:571:20)
at Socket._read (net.js:582:5)
at Socket.Readable.read (_stream_readable.js:474:10)
at Socket.read (net.js:622:39)
at new Socket (net.js:374:12)
at Object.Socket (net.js:265:41)
at createSocket (internal/child_process.js:313:14)
at ChildProcess.spawn (internal/child_process.js:436:23)
at Object.spawn (child_process.js:548:9)
at spawn (/Users/daddy/Dev/scout/project-sunroof-scraping/node_modules/cross-spawn/index.js:17:18)
at gm._spawn (/Users/daddy/Dev/scout/project-sunroof-scraping/node_modules/gm/lib/command.js:224:14)
at /Users/daddy/Dev/scout/project-sunroof-scraping/node_modules/gm/lib/command.js:101:12
at series (/Users/daddy/Dev/scout/project-sunroof-scraping/node_modules/array-series/index.js:11:36)
at gm._preprocess (/Users/daddy/Dev/scout/project-sunroof-scraping/node_modules/gm/lib/command.js:177:5)
at gm.write (/Users/daddy/Dev/scout/project-sunroof-scraping/node_modules/gm/lib/command.js:99:10)
at /Users/daddy/Dev/scout/project-sunroof-scraping/modules/changeScreenshotDPI.js:18:26
Emitted 'error' event on Socket instance at:
at emitErrorNT (internal/streams/destroy.js:100:8)
at emitErrorCloseNT (internal/streams/destroy.js:68:3)
at processTicksAndRejections (internal/process/task_queues.js:84:21) {
errno: -57,
code: 'ENOTCONN',
syscall: 'read'
}

Getting A “Cast to ObjectId” Error With Heroku, But Not With LocalHost?

My 'lessons/new' page loads fine on my localhost, but gives an error with heroku. The page will load, but it crashes immediately after in heroku. I added a console.log(foundClass) for getClassesById and the foundClass dislplayed correctly. Can someone please point me in the right direction?
class.js lines 27-33
module.exports.getClassesById = function(id, callback){
Class.findById(id)
.populate(
{path: 'lessons',
model: 'Lesson', $ne: null}
).exec(callback)
}
classes.js
router.get('/:id/lessons/new', function(req, res, next) {
Class.getClassesById([req.params.id], function(err, foundClass){
if (err){
console.log(err)
throw err
} else {
if (req.user && req.user.email == foundClass.instructor_email){
res.render('lessons/new', {class_id: req.params.id})
} else {
res.redirect('/');
}
}
})
});
heroku logs
2016-10-24T17:31:08.413872+00:00 app[web.1]: [0mGET /classes/580e0e820a1e5d00118e6159/lessons/new [36m304 [0m30.674 ms - -[0m
2016-10-24T17:31:08.486402+00:00 app[web.1]: [0mGET /stylesheets/bootstrap.min.css [36m304 [0m2.559 ms - -[0m
2016-10-24T17:31:08.486823+00:00 app[web.1]: [0mGET /stylesheets/style.css [36m304 [0m2.326 ms - -[0m
2016-10-24T17:31:08.487513+00:00 app[web.1]: [0mGET /stylesheets/ie10-viewport-bug-workaround.css [36m304 [0m2.315 ms - -[0m
2016-10-24T17:31:08.489252+00:00 app[web.1]: [0mGET /stylesheets/jumbotron.css [36m304 [0m3.708 ms - -[0m
2016-10-24T17:31:08.529026+00:00 app[web.1]: [0mGET /js/bootstrap.min.js [36m304 [0m2.226 ms - -[0m
2016-10-24T17:31:08.530994+00:00 app[web.1]: [0mGET /js/ie10-viewport-bug-workaround.js [36m304 [0m0.699 ms - -[0m
2016-10-24T17:31:09.037191+00:00 app[web.1]: { CastError: Cast to ObjectId failed for value "[ 'favicon.ico' ]" at path "_id"
2016-10-24T17:31:09.037205+00:00 app[web.1]: at MongooseError.CastError (/app/node_modules/mongoose/lib/error/cast.js:26:11)
2016-10-24T17:31:09.037206+00:00 app[web.1]: at ObjectId.cast (/app/node_modules/mongoose/lib/schema/objectid.js:147:13)
2016-10-24T17:31:09.037207+00:00 app[web.1]: at ObjectId.castForQuery (/app/node_modules/mongoose/lib/schema/objectid.js:187:15)
2016-10-24T17:31:09.037208+00:00 app[web.1]: at cast (/app/node_modules/mongoose/lib/cast.js:225:32)
2016-10-24T17:31:09.037209+00:00 app[web.1]: at Query.cast (/app/node_modules/mongoose/lib/query.js:2737:10)
2016-10-24T17:31:09.037209+00:00 app[web.1]: at Query.findOne (/app/node_modules/mongoose/lib/query.js:1350:10)
2016-10-24T17:31:09.037210+00:00 app[web.1]: at /app/node_modules/mongoose/lib/query.js:2296:21
2016-10-24T17:31:09.037210+00:00 app[web.1]: at new Promise.ES6 (/app/node_modules/mongoose/lib/promise.js:45:3)
2016-10-24T17:31:09.037211+00:00 app[web.1]: at Query.exec (/app/node_modules/mongoose/lib/query.js:2290:17)
2016-10-24T17:31:09.037211+00:00 app[web.1]: at Function.module.exports.getClassesById (/app/models/class.js:32:4)
2016-10-24T17:31:09.037212+00:00 app[web.1]: at /app/routes/classes.js:105:8
2016-10-24T17:31:09.037213+00:00 app[web.1]: at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:82:5)
2016-10-24T17:31:09.037213+00:00 app[web.1]: at next (/app/node_modules/express/lib/router/route.js:110:13)
2016-10-24T17:31:09.037214+00:00 app[web.1]: at Route.dispatch (/app/node_modules/express/lib/router/route.js:91:3)
2016-10-24T17:31:09.037214+00:00 app[web.1]: at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:82:5)
2016-10-24T17:31:09.037214+00:00 app[web.1]: at /app/node_modules/express/lib/router/index.js:267:22
2016-10-24T17:31:09.037215+00:00 app[web.1]: at param (/app/node_modules/express/lib/router/index.js:340:14)
2016-10-24T17:31:09.037215+00:00 app[web.1]: at param (/app/node_modules/express/lib/router/index.js:356:14)
2016-10-24T17:31:09.037216+00:00 app[web.1]: at Function.proto.process_params (/app/node_modules/express/lib/router/index.js:400:3)
2016-10-24T17:31:09.037216+00:00 app[web.1]: at next (/app/node_modules/express/lib/router/index.js:261:10)
2016-10-24T17:31:09.037216+00:00 app[web.1]: at Function.proto.handle (/app/node_modules/express/lib/router/index.js:166:3)
2016-10-24T17:31:09.037217+00:00 app[web.1]: at router (/app/node_modules/express/lib/router/index.js:35:12)
2016-10-24T17:31:09.037217+00:00 app[web.1]: message: 'Cast to ObjectId failed for value "[ \'favicon.ico\' ]" at path "_id"',
2016-10-24T17:31:09.037218+00:00 app[web.1]: name: 'CastError',
2016-10-24T17:31:09.037218+00:00 app[web.1]: kind: 'ObjectId',
2016-10-24T17:31:09.037218+00:00 app[web.1]: value: [ 'favicon.ico' ],
2016-10-24T17:31:09.037219+00:00 app[web.1]: path: '_id',
2016-10-24T17:31:09.037219+00:00 app[web.1]: reason: undefined }
2016-10-24T17:31:09.038731+00:00 app[web.1]:
2016-10-24T17:31:09.038733+00:00 app[web.1]: events.js:160
2016-10-24T17:31:09.038734+00:00 app[web.1]: throw er; // Unhandled 'error' event
2016-10-24T17:31:09.038734+00:00 app[web.1]: ^
2016-10-24T17:31:09.038768+00:00 app[web.1]: CastError: Cast to ObjectId failed for value "[ 'favicon.ico' ]" at path "_id"
2016-10-24T17:31:09.038769+00:00 app[web.1]: at MongooseError.CastError (/app/node_modules/mongoose/lib/error/cast.js:26:11)
2016-10-24T17:31:09.038770+00:00 app[web.1]: at ObjectId.cast (/app/node_modules/mongoose/lib/schema/objectid.js:147:13)
2016-10-24T17:31:09.038771+00:00 app[web.1]: at ObjectId.castForQuery (/app/node_modules/mongoose/lib/schema/objectid.js:187:15)
2016-10-24T17:31:09.038771+00:00 app[web.1]: at cast (/app/node_modules/mongoose/lib/cast.js:225:32)
2016-10-24T17:31:09.038772+00:00 app[web.1]: at Query.cast (/app/node_modules/mongoose/lib/query.js:2737:10)
2016-10-24T17:31:09.038773+00:00 app[web.1]: at Query.findOne (/app/node_modules/mongoose/lib/query.js:1350:10)
2016-10-24T17:31:09.038773+00:00 app[web.1]: at /app/node_modules/mongoose/lib/query.js:2296:21
2016-10-24T17:31:09.038774+00:00 app[web.1]: at new Promise.ES6 (/app/node_modules/mongoose/lib/promise.js:45:3)
2016-10-24T17:31:09.038774+00:00 app[web.1]: at Query.exec (/app/node_modules/mongoose/lib/query.js:2290:17)
2016-10-24T17:31:09.038775+00:00 app[web.1]: at Function.module.exports.getClassesById (/app/models/class.js:32:4)
2016-10-24T17:31:09.038776+00:00 app[web.1]: at /app/routes/classes.js:105:8
2016-10-24T17:31:09.038776+00:00 app[web.1]: at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:82:5)
2016-10-24T17:31:09.038777+00:00 app[web.1]: at next (/app/node_modules/express/lib/router/route.js:110:13)
2016-10-24T17:31:09.038778+00:00 app[web.1]: at Route.dispatch (/app/node_modules/express/lib/router/route.js:91:3)
2016-10-24T17:31:09.038778+00:00 app[web.1]: at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:82:5)
2016-10-24T17:31:09.038779+00:00 app[web.1]: at /app/node_modules/express/lib/router/index.js:267:22
2016-10-24T17:31:09.038779+00:00 app[web.1]: at param (/app/node_modules/express/lib/router/index.js:340:14)
2016-10-24T17:31:09.038780+00:00 app[web.1]: at param (/app/node_modules/express/lib/router/index.js:356:14)
2016-10-24T17:31:09.038780+00:00 app[web.1]: at Function.proto.process_params (/app/node_modules/express/lib/router/index.js:400:3)
2016-10-24T17:31:09.038781+00:00 app[web.1]: at next (/app/node_modules/express/lib/router/index.js:261:10)
2016-10-24T17:31:09.038781+00:00 app[web.1]: at Function.proto.handle (/app/node_modules/express/lib/router/index.js:166:3)
2016-10-24T17:31:09.038782+00:00 app[web.1]: at router (/app/node_modules/express/lib/router/index.js:35:12)
2016-10-24T17:31:09.051877+00:00 app[web.1]:
2016-10-24T17:31:09.059912+00:00 app[web.1]: npm ERR! Linux 3.13.0-100-generic
2016-10-24T17:31:09.060095+00:00 app[web.1]: npm ERR! argv "/app/.heroku/node/bin/node" "/app/.heroku/node/bin/npm" "start"
2016-10-24T17:31:09.060223+00:00 app[web.1]: npm ERR! node v6.6.0
2016-10-24T17:31:09.060321+00:00 app[web.1]: npm ERR! npm v3.10.3
2016-10-24T17:31:09.060423+00:00 app[web.1]: npm ERR! code ELIFECYCLE
2016-10-24T17:31:09.060516+00:00 app[web.1]: npm ERR! eTeacher#0.0.1 start: `node ./bin/www`
2016-10-24T17:31:09.060581+00:00 app[web.1]: npm ERR! Exit status 1
2016-10-24T17:31:09.060664+00:00 app[web.1]: npm ERR!
2016-10-24T17:31:09.060738+00:00 app[web.1]: npm ERR! Failed at the eTeacher#0.0.1 start script 'node ./bin/www'.
2016-10-24T17:31:09.060808+00:00 app[web.1]: npm ERR! Make sure you have the latest version of node.js and npm installed.
2016-10-24T17:31:09.060873+00:00 app[web.1]: npm ERR! If you do, this is most likely a problem with the eTeacher package,
2016-10-24T17:31:09.060940+00:00 app[web.1]: npm ERR! not with npm itself.
2016-10-24T17:31:09.061016+00:00 app[web.1]: npm ERR! Tell the author that this fails on your system:
2016-10-24T17:31:09.061085+00:00 app[web.1]: npm ERR! node ./bin/www
2016-10-24T17:31:09.061153+00:00 app[web.1]: npm ERR! You can get information on how to open an issue for this project with:
2016-10-24T17:31:09.061212+00:00 app[web.1]: npm ERR! npm bugs eTeacher
2016-10-24T17:31:09.061280+00:00 app[web.1]: npm ERR! Or if that isn't available, you can get their info via:
2016-10-24T17:31:09.061347+00:00 app[web.1]: npm ERR! npm owner ls eTeacher
2016-10-24T17:31:09.061415+00:00 app[web.1]: npm ERR! There is likely additional logging output above.
2016-10-24T17:31:09.065020+00:00 app[web.1]:
2016-10-24T17:31:09.065328+00:00 app[web.1]: npm ERR! Please include the following file with any support request:
2016-10-24T17:31:09.065465+00:00 app[web.1]: npm ERR! /app/npm-debug.log
Class schema
var classSchema = new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
instructor: { type: String, required: true },
instructor_email: { type: String, required: true },
//Lessons for the class
lessons: [
{ type: mongoose.Schema.Types.ObjectId, ref: 'Lesson' }
],
category: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' },
created : { type : Date, default : Date.now }
});
'classes/show' is the page it is coming from
classes.js 104-114
router.get('/:id', function(req, res, next) {
Class.getClassesById([req.params.id], function(err, foundClass){
if (err){
console.log(err)
throw err
} else {
console.log('Found class.')
res.render('classes/show', {"class": foundClass})
}
});
});
It's giving that error because Mongo ID is supposed to be of a specific format. The error log says that it got "favicon.ico" as a param which violates the Mongo ID format.
You should validate the data ALWAYS before doing DB operations.
There's a package for string validation and sanitization: https://www.npmjs.com/package/validator
You can check if the param is in proper format by:
var validator = require('validator');
then in your route:
if (!validator.isMongoId(req.params.id)) {
// Param is not mongoId, throw error
}

Node.js and Sendgrid mailer error on res.end

I'm a bit new to node. I'm using express and the sendgrid api to send an email (collected REST-fully). After sendgrid succeeds or fails, I want to respond with a json object. Here's the sample case:
var SendGrid = require('sendgrid-nodejs').SendGrid;
var sendgrid = new SendGrid(user, key);
app.get('/LGP/:email', function (req, res){
sendgrid.send({
to: req.params.email,
from: 'me#example.com',
subject: 'Hello World',
text: 'This email sent through SendGrid'
}, function(success, message) {
if (!success) {
console.log(message);
} else {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.write(JSON.stringify({ result: 'success' }));
res.end(); //error occurs: "Can't use mutable header APIs after sent."
}
}
);
});
On my local server (using foreman), everything works fine. But when I push it to heroku, it gives me this stack trace:
2013-02-27T22:12:46+00:00 app[web.1]: http.js:543
2013-02-27T22:12:46+00:00 app[web.1]: throw new Error("Can't use mutable header APIs after sent.");
2013-02-27T22:12:46+00:00 app[web.1]: ^
2013-02-27T22:12:46+00:00 app[web.1]: Error: Can't use mutable header APIs after sent.
2013-02-27T22:12:46+00:00 app[web.1]: at ServerResponse.getHeader (http.js:543:11)
2013-02-27T22:12:46+00:00 app[web.1]: at /app/node_modules/express/node_modules/connect/lib/middleware/logger.js:229:26
2013-02-27T22:12:46+00:00 app[web.1]: at ServerResponse.<anonymous> (/app/node_modules/express/node_modules/connect/lib/middleware/logger.js:149:20)
2013-02-27T22:12:46+00:00 app[web.1]: at /app/app.js:60:13
2013-02-27T22:12:46+00:00 app[web.1]: at IncomingMessage.<anonymous> (/app/node_modules/sendgrid/lib/sendgrid.js:74:9)
2013-02-27T22:12:46+00:00 app[web.1]: at IncomingMessage.emit (events.js:81:20)
2013-02-27T22:12:46+00:00 app[web.1]: at HTTPParser.onMessageComplete (http.js:133:23)
2013-02-27T22:12:46+00:00 app[web.1]: at CleartextStream.ondata (http.js:1213:22)
2013-02-27T22:12:46+00:00 app[web.1]: at CleartextStream._push (tls.js:291:27)
2013-02-27T22:12:46+00:00 app[web.1]: at SecurePair._cycle (tls.js:565:20)
2013-02-27T22:12:48+00:00 heroku[web.1]: Process exited with status 1
2013-02-27T22:12:48+00:00 heroku[web.1]: State changed from up to crashed
/app/app.js:60:13 refers to the line with "res.end()". What am I doing wrong?
To maximize your chances of your app behaving the same locally and on heroku, you should make sure you specify specific versions for all modules and avoid using "*" for the main dependencies.
Should also should specify the node version in package.json:
"engines": {
"node": "0.8.20"
}
(use whatever version is appropriate).

Resources