{"record":{"id":"e0630521193510c5","repo":"balderdashy/sails","slug":"streaming-file-uploads-via-req-file-are-only-a","errorCode":null,"errorMessage":"Streaming file uploads via `req.file()` are only available over HTTP with Skipper.","messagePattern":"Streaming file uploads via `req\\.file\\(\\)` are only available over HTTP with Skipper\\.","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"lib/router/index.js","lineNumber":524,"sourceCode":"// Extremely simple query string parser (`req.query`)\nfunction qsParser(req,res,next) {\n  var queryStringPos = req.url.indexOf('?');\n  if (queryStringPos !== -1) {\n    req.query = _.merge(req.query, QS.parse(req.url.substr(queryStringPos + 1)));\n  }\n  else {\n    req.query = req.query || {};\n  }\n  next();\n}\n// Extremely simple body parser (`req.body`)\nfunction bodyParser (req, res, next) {\n\n  // Set up a mock `req.file()` clarifying that req.file() is not available\n  // outside of the context of Skipper (i.e. in this case, most commonly from\n  // socket.io virtual requests).\n  req.file = function fileUploadsNotAvailable(){\n    return res.status(500).send('Streaming file uploads via `req.file()` are only available over HTTP with Skipper.');\n  };\n\n  var bodyBuffer='';\n  if (req.method === 'GET' || req.method === 'HEAD' || req.method === 'DELETE'){\n    req.body = _.extend({}, req.body);\n    return next();\n  }\n\n  // Ensure that `req` is a readable stream at this point\n  if ( !(req instanceof Readable) ) {\n    return next(new Error('Sails Internal Error: `req` should be a Readable stream by the time `route()` is called'));\n  }\n\n  req.on('readable', function() {\n    var chunk;\n    while (null !== (chunk = req.read())) {\n      bodyBuffer += chunk;\n    }","sourceCodeStart":506,"sourceCodeEnd":542,"githubUrl":"https://github.com/balderdashy/sails/blob/7b76422cc27823df033572bdda5c4910a68b697f/lib/router/index.js#L506-L542","documentation":"Sails replaces req.file() with a stub outside Skipper's HTTP handling (most commonly on socket.io virtual requests) that immediately responds 500 with this exact message. Streaming multipart file uploads only work over real HTTP requests where Skipper is installed as the body parser.","triggerScenarios":"Calling req.file('avatar').upload(...) inside a controller action reached via a socket.io virtual request (io.socket.post), or via any route path where Skipper's body parser is not active (e.g. bodyParser overridden in config.http.middleware).","commonSituations":"Attempting file upload through socket.io from sails.io.js client; custom middleware order in config/http.js that skips Skipper; calling upload endpoints from mobile SDKs over websockets.","solutions":["Perform the upload over plain HTTP (fetch/XHR/form POST) instead of io.socket.post.","Verify sails.config.http.middleware.order includes 'bodyParser' and that it maps to Skipper (sails-hook-requests defaults).","Guard server-side: check req.is('multipart/form-data') and reject socket-originated uploads early.","For socket clients, upload via a signed HTTP URL and only notify completion over the socket."],"exampleFix":"// before\nio.socket.post('/upload', formData, cb); // hits stub req.file()\n// after\nfetch('/upload', { method: 'POST', body: formData }).then(cb);","handlingStrategy":"fallback","validationCode":"function canUpload(req) {\n  return typeof req.file === 'function' &&\n    !req.file.toString().includes('fileUploadsNotAvailable') &&\n    req.is('multipart/form-data');\n}","typeGuard":"function skipperAvailable(req) { return typeof req.file === 'function' && req._fileparser instanceof Object; }","tryCatchPattern":"if (typeof req.file !== 'function' || isVirtualRequest(req)) {\n  return res.badRequest('Uploads require an HTTP request');\n}\ntry {\n  await req.file('avatar').upload({ dirname: dir }, cb);\n} catch (e) {\n  return res.serverError(e);\n}","preventionTips":["Always upload files via HTTP, never io.socket","Keep bodyParser (Skipper) in config.http.middleware.order","Check req.wantsJSON/socket origin before calling req.file()","Provide an HTTP upload endpoint for socket-connected clients"],"tags":["file-upload","skipper","socket-io","unsupported"],"backgroundTag":"file-upload-not-supported-over-socket","analyzedSha":"7b76422cc27823df033572bdda5c4910a68b697f","analyzedAt":"2026-09-01T04:01:57.104Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}