NodeJS error with connect-busboy, "TypeError: Cannot call method 'on' of undefined"

5.5k views Asked by At

I have this piece of code:

router.route("/post")
        .get(function(req, res) {
            ...
        })
        .post(authReq, function(req, res) {
            ...
            // Get uploaded file
            var fstream
            req.pipe(req.busboy)
            req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
            ...

            var fileSuffix = mimetype.split("/")[1] // Get suffix, may not always be correct
            var tmpFileName = postCount + "." + fileSuffix
            var tmpFileURL = __dirname + "/tmp/" + tmpFileName
            // Start writing
            fstream = fs.createWriteStream(tmpFileURL)
            file.pipe(fstream)
            fstream.on('close', function() {
                 ...
            })
        })
    })
})

This use to work perfectly. However, I don't know quite what happened, but I picked up my computer today and found this error occurring every time I attempt to post:

TypeError: Cannot call method 'on' of undefined
    at IncomingMessage.Readable.pipe (_stream_readable.js:494:8)
    at /Users/nathan/Library/Mobile Documents/com~apple~CloudDocs/Dev/LaughItUp/Code/Server/apiRoutes.js:139:8
    at Layer.handle [as handle_request] (/Users/nathan/Library/Mobile Documents/com~apple~CloudDocs/Dev/LaughItUp/Code/Server/node_modules/express/lib/router/layer.js:82:5)
    at next (/Users/nathan/Library/Mobile Documents/com~apple~CloudDocs/Dev/LaughItUp/Code/Server/node_modules/express/lib/router/route.js:100:13)
    at authReq (/Users/nathan/Library/Mobile Documents/com~apple~CloudDocs/Dev/LaughItUp/Code/Server/apiRoutes.js:17:3)
    at Layer.handle [as handle_request] (/Users/nathan/Library/Mobile Documents/com~apple~CloudDocs/Dev/LaughItUp/Code/Server/node_modules/express/lib/router/layer.js:82:5)
    at next (/Users/nathan/Library/Mobile Documents/com~apple~CloudDocs/Dev/LaughItUp/Code/Server/node_modules/express/lib/router/route.js:100:13)
    at next (/Users/nathan/Library/Mobile Documents/com~apple~CloudDocs/Dev/LaughItUp/Code/Server/node_modules/express/lib/router/route.js:94:14)
    at Route.dispatch (/Users/nathan/Library/Mobile Documents/com~apple~CloudDocs/Dev/LaughItUp/Code/Server/node_modules/express/lib/router/route.js:81:3)
    at Layer.handle [as handle_request] (/Users/nathan/Library/Mobile Documents/com~apple~CloudDocs/Dev/LaughItUp/Code/Server/node_modules/express/lib/router/layer.js:82:5)

_stream_readable.js:501
    dest.end();
         ^
TypeError: Cannot call method 'end' of undefined
    at IncomingMessage.onend (_stream_readable.js:501:10)
    at IncomingMessage.g (events.js:180:16)
    at IncomingMessage.emit (events.js:92:17)
    at _stream_readable.js:943:16
    at process._tickCallback (node.js:419:13)

In my index.js file, I have this code to use Busboy:

app.use(busboy())

Then this code to include my route:

app.use("/api", require("./apiRoutes.js")())

Thanks in advance!

EDIT: I was doing a bit more debugging and I think I pinpointed the issue. req.busboy is not defined. So I went digging through source code. Here is some of the code in the connect-busboy module:

if (req.busboy
|| req.method === 'GET'
|| req.method === 'HEAD'
|| !hasBody(req)
|| !RE_MIME.test(mime(req)))
return next()

When I print out the actual values, busboy does not exist, the request method is 'POST', hasBody(req) results true, yet RE_MIME.test(mime(req))) results false, which is why busboy is not added to the request.

My example file's MIME type is image/gif. Here is the regular expression connect-busboy is testing image/gif off of (aka RE_MIME variable):

/^(?:multipart\/.+)|(?:application\/x-www-form-urlencoded)$/i;

Therefore, I've come to the verdict I'm misunderstanding the API. Is Busboy only for HTML forms?

EDIT #2: I simply switched to Multer and it works fine. However, I believe my issue was that I needed to place the file in a multipart part of the request; I'm not sure why it was working before. Thanks!

2

There are 2 answers

0
mscdex On BEST ANSWER

The problem is that your request is not multipart/form-data, but image/gif instead. Busboy, multer, formidable, multiparty, etc. cannot parse the request unless it's multipart/form-data (if you are uploading a file).

0
drdmitry On

Make sure you have in your index.js file:

var busboy = require('connect-busboy');
// ...
var app = express();
// ...
// and
app.use(busboy()); // I had exact the same error when this line was missing in index.js