Error Received: Source.on is not a function

Hello Team,

I am trying to create a ticket in Freshdesk along with attachments, but I am getting an error.

The Error is:

TypeError: source.on is not a function
    at Function.DelayedStream.create (/usr/local/lib/node_modules/fdk/node_modules/delayed-stream/lib/delayed_stream.js:33:10)
    at FormData.CombinedStream.append (/usr/local/lib/node_modules/fdk/node_modules/combined-stream/lib/combined_stream.js:45:37)
    at FormData.append (/usr/local/lib/node_modules/fdk/node_modules/request/node_modules/form-data/lib/form_data.js:74:3)
    at appendFormValue (/usr/local/lib/node_modules/fdk/node_modules/request/request.js:326:21)
    at Request.init (/usr/local/lib/node_modules/fdk/node_modules/request/request.js:337:11)
    at new Request (/usr/local/lib/node_modules/fdk/node_modules/request/request.js:127:8)
    at Function.request (/usr/local/lib/node_modules/fdk/node_modules/request/index.js:53:10)
    at Request._tryUntilFail (/usr/local/lib/node_modules/fdk/node_modules/requestretry/index.js:124:23)
    at Factory (/usr/local/lib/node_modules/fdk/node_modules/requestretry/index.js:178:7)
    at Object.execute (/usr/local/lib/node_modules/fdk/lib/api/proxy.js:171:12)

My code:

var base64 = require('base-64');
exports = {
  events: [{
    event: 'onConversationCreate',
    callback: 'onConversationCreateHandler'
  }],
  onConversationCreateHandler: function (args) {
    console.log('onConversationCreateHandler event');
    test();
  }
};

function test() {
  console.log("in testttttttttttttt");
  var url = "https://xxxxxxxxxxx.freshdesk.com/api/v2/tickets";
  var apiKEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
  var headers = {
    "Content-Type": "multipart/form-data",
    "Authorization": "Basic " + base64.encode(apiKEY)
  };
  var a = {
    "file": "/home/artis/Music/ask"
  };
  var formData = {
    "description": "support ticket....",
    "subject": "support ticket...",
    "email": "tcheekati@artissol.com",
    "attachments[]": a
  };
  var options = {
    formData: formData,
    headers: headers
  };
  console.log(url);
  console.log(options);
  $request.post(url, options).then(function (data) {
    console.log("sssssssssssssssssssssssssss", data);
  }, function (error) {
    console.log(error);
  });
}

Regards,
Akhil S Kulkarni

Hello Guys,

Can someone please help me with the issue?

Regards,
Akhil S Kulkarni

hey @Akhil_Kulkarni

$request doesn’t support file attachment, to overcome this you can use external http packages such as axios

@Akhil_Kulkarni, Were you able to have this issue solved?

Hi @Akhil_Kulkarni

The reason why TypeError: source.on... error occurs in this context is primarily because formData accepts only String / Buffer / Stream types for its properties. A straightforward solution would be to convert it to one of those types. However, that leads us to couple of other issues

  • JSON.stringify() on file object is not going to work the way we expect and will technically result in an error
{"description":"Validation failed","errors":[{"field":"attachments",
"message":"It should contain elements of type valid file format only",
"code":"datatype_mismatch"}]}
  • The right choice would be to create a readable file stream. However, since our app runs in AWS lambda, maintaining files/assets inside the app won’t scale and would be technically challenging. If it were a local machine or a secure middleware running the logic, fs would be handy in creating a stream and it can be appropriately passed while making the call

As I see from your code, the intent is to attach a specific file during ticket creation. I just gave a shot with unirest NPM package - which has a simpler interface and also supports reading remote file streams. This also could keep the middleware lean. For example,

var unirest = require('unirest');

exports = {
  events: [{
    event: 'onAppInstall',
    callback: 'aiHandler'
  }],
  aiHandler: function (args) {
    /* Substitute with the right handler and event. This is just to demo */
    logger('--Inside App Install Handler--');
    logger(args);
    attFile();
    renderData();
  }
};

function attFile(){
  logger("--Let's attach a file --");
  var url = "https://xxx.freshdesk.com/api/v2/tickets";
  var apiKEY = "yyy";
  var headers = {
    "Content-Type": "multipart/form-data",
    "Authorization": "Basic " + apiKEY
  };
  var fields = {
    "description": "support ticket....",
    "subject": "support ticket...",
    "email": "example@example.com",
    "status":"2", // certain fields are required during creation
    "priority":"1"
  };
// Lets make use of unirest to attach files from our secure file store/s3/...
  unirest.post(url)
  .headers(headers)
  .field(fields)
  .attach('attachments[]', 'https://i.imgur.com/lcB62xb.jpg')
  .attach('attachments[]', 'https://gist.githubusercontent.com/hemchander23/6708ad5595dd56ef31087d47d4f96a44/raw/89ab0df9685cac94bbb88e1ebfd3655bcade6c9d/DarkS1E4_Script.txt#')
  .attach('attachments[]', 'https://www.gstatic.com/covid19/mobility/2020-05-25_US_Mobility_Report_en.pdf')
  .end(function(response){
    logger(response.body)
    logger("Response Status : " + response.status)
    if(response.status == 201){
      logger("Location Header : "+ response.headers['location'])
    }
    else{
      logger("X-Request-Id :" + response.headers['x-request-id']);
    }
  });
}


function logger(dat){
  console.log(dat);
}

will create a ticket like so:

It is very important to note that the file storage service that you use has to be secure and must generate short-lived (possibly signed as well) links that are only valid for the ticket creation session. Upon creation of the ticket, you will notice that the attachments have a link of their own.