question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`source.on is not a function` from form-data when attaching a file

See original GitHub issue

It looks like I’m hitting https://github.com/request/request/issues/1495 when trying to use superagent for an asynchronous file uploader.

export default class ApiClient {                 
  static asyncUpload(file, siteCompanyId) {      
    return new Promise((resolve, reject) => {    
      superagent                                 
      .post('/client_api/upload_file')           
      .field('file', file)                       
      .end( (err, res) => {                      
        if (err || !res.status == 'ok') {        
          reject(res);                           
        } else {                                 
          resolve(res.body);                     
        }                                        
      });                           
  }                                              
}

This seems to work just fine in my browser, but when I try to run my tests I get

1) ApiClient asyncUpload should send file data to the server:
   TypeError: source.on is not a function
    at Function.DelayedStream.create (node_modules/delayed-stream/lib/delayed_stream.js:33:10)
    at FormData.CombinedStream.append (node_modules/combined-stream/lib/combined_stream.js:43:37)
    at FormData.append (node_modules/form-data/lib/form_data.js:68:3)
    at Request.exports.field (node_modules/superagent/lib/request-base.js:209:23)
    at frontend/applicant/js/api_client.js:11:10
    at Function.asyncUpload (frontend/applicant/js/api_client.js:9:10)
    at Context.<anonymous> (frontend/applicant/js/test/api_client.spec.js:33:4)

The test looks like

describe('asyncUpload', function() {
  it('should send file data to the server', () => {
    // prepare test articles
    let file = {
      "name": "blah.txt",
      "size": 6,
      "type": "text/plain",
    };

    // prepare http interceptor
    nock('http://localhost/')
      .post('/client_api/upload_file', {
        file: file,
      })
      .reply(200, {
        status: 'ok',
        payload: {
          appfileId: 43,
        },
      });

    return ApiClient.asyncUpload(file, siteCompanyId).then( (data) => {
      console.log('test then');
    });
});

From yarn.lock:

superagent:
  version "2.3.0"
  resolved "https://registry.yarnpkg.com/superagent/-/superagent-2.3.0.tgz#703529a0714e57e123959ddefbce193b2e50d115"
  dependencies:
    component-emitter "^1.2.0"
    cookiejar "^2.0.6"
    debug "^2.2.0"
    extend "^3.0.0"
    form-data "1.0.0-rc4"
    formidable "^1.0.17"
    methods "^1.1.1"
    mime "^1.3.4"
    qs "^6.1.0"
    readable-stream "^2.0.5"

and

∙ node -v  
-64

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:1
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
vinnymaccommented, Jul 15, 2019

I ran into this issue on v3.8.3 of an old project I maintain. If your test has control of the file being passed to attach. You can easily workaround this problem by doing the following.

import request from 'superagent'

function testUpload(url, mockFile, errorHandler) {
  const r = request.post(url)
      .field({ name: 'cat.gif' })
      .attach('file', mockFile, mockFile.name)
      .on('error', errorHandler)

  Object.assign(mockFile, {
    on: () => {},
    pause: () => {},
    resume: () => {},
  })

  return r
}

It seems the file ends up being considered the stream in delayed_stream.js and combined_stream.js, so forcing those methods to be defined gets around it. You can go further and use mock implementations if you needed to.

Just wanted to share for others who may be stuck on an older version or are still experiencing this problem.

0reactions
EduardoFLimacommented, May 12, 2020

Just bumped into the same issue on version 5.2.2. @vinnymac solution helped but didn’t solve the problem because I’m using nock for mocking the request result and now it is timing out - probably because of these mocks (on/pause/resume).

What solved to me was, instead of attaching the file, sending a FormData:

let formData = new FormData();
formData.append('file', file);

request.post(uri)
       .send(formData); 
Read more comments on GitHub >

github_iconTop Results From Across the Web

TypeError: source.on is not a function · Issue #2366 - GitHub
I'm trying to POST an array of values to a HTTP endpoint, and this is the error I receive: TypeError: source.on is not...
Read more >
Getting ERROR: uncaughtException: source.on is not a ...
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...
Read more >
Error Received: Source.on is not a function - App Platform
Hello Team, I am trying to create a ticket in Freshdesk along with attachments, but I am getting an error. The Error is:...
Read more >
FormData.append() - Web APIs | MDN
The append() method of the FormData interface appends a new value onto an existing key inside a FormData object, or adds the key...
Read more >
Send a File With Axios in Node.js - Maxim Orlov
Only if uploading files with axios in Node.js would be as easy as taking a ... a new FormData instance and use the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found