[Resolved] How are people handling server-side Stripe errors?


#1

Given the open Meteor.wrapAsync bug - how are people currently generating useful errors for Stripe payments?

For example I have the following code within a method that creates a Stripe subscription for a given customer. This is the point that the previously created card token is charged (or attempted) and so the point that potentially generates invalid card detail errors (such as if the CVV number is wrong, or the card number is valid, but incorrect).

var CreateSubscription = Meteor.wrapAsync(Stripe.customers.createSubscription, Stripe.customers);
try{
  var subscription = CreateSubscription(customer.id, { plan: plan, source: stripeToken });
  Meteor.users.update( { _id: Meteor.userId() }, {$set: { 'sub.periodEnd': subscription.current_period_end }});
}
catch (error) {
  console.log(error);
  throw new Meteor.Error( 500, "Couldn't create subscription" );
}

The problem is all I can get out of the catch is:

Exception while invoking method 'StripeCreateSubscription' undefined

(StripeCreateSubscription being the name of the method that contains the above code).

The undefined at the end is from the console log, as for whatever reason the error object in the catch is empty.

The only solution I can think of is to display a generic ‘There was a problem with the details you provided’ type error - but this is a bit risky, as if there’s a more general error, or communication issue, I don’t want to be giving the user incorrect and potentially frustrating information.


#2

an potential workaround though not the best of workarounds would be to just have a field on the user record updated with the error. If you wanted to make sure old errors didnt’ appear. You can apply a timestamp to the field entry as well. Have the aysnc method load the return error into that field and that have it displayed to the user with blaze.

If you wanted something a bit more protective of passing incorrect errors. Have the field pass back an unique identifier that you pass into the method when you clicked submit. That way you can confirm that the error your passing is the error the user is experiencing at that moment.


#3

That’s a novel approach, interesting thinking - however the error doesn’t actually seem to be available - so how would I get it into the user document? (See the undefined when attempting to log the error object). Otherwise I could probably also use the session etc to achieve the same, without the extra I/O.


#4

Sorry I had skimmed through it.

You’re not returning the error on the async function. The last variable should be where you tell the async variable where to return. I.e

asyncFunc(params,function(error,result) {
if(error){
console.log(“error”,error);
return;
}
console.log(“result :”,result);
});

so for your’s:

var CreateSubscription = Meteor.wrapAsync(Stripe.customers.createSubscription, Stripe.customers, function(error, result) {
if (error) { return error; } else { return result; }
});

Edit: Sorry for the grammar. The coffee has not kicked in yet

Edit2: You can’t use session set since the actions are occurring and need to occur on the server side (methods).


#5

Maybe I’m mistaken, but functionally isn’t return error identical to throw new Meteor.Error( 500, "Couldn't create subscription" );? (my reading of ‘throw’ indicated as much anyway).

Besides, importantly the error object is undefined. So it doesn’t matter how I return it - you can see right in my example that the console can’t even log it - this is a known bug with Meteor.wrapAsync as stated in the OP. Edit: Looking over the issue again I may have slightly misunderstood it, happy to be corrected here, but either way it seems I’m not going to be able to get anything more useful than a generic error?

(But yea, good point about the session!)


#6

Did some searching. This may help to understand

edit: In order to throw the error you need to receive. You need to the tell the function within the aysnc function to pass the error to the async which then try/catch can then pick it up and then do what you need to do with it.


#7

I had the same issue but got it to work.
Try this catch block on the server:

 catch (exception) {
           throw new Meteor.Error(exception.code);
 }

On the client, the detailed error message from Stripe will be then available in the callback. You can read it from error.error

PS: You can create a customer and add a subscription at the same time too:

var syncCustomerCreateFunction = Meteor.wrapAsync(Stripe.customers.create, Stripe.customers);
try {
      var result = syncCustomerCreateFunction({
          source: token,
          plan: plan
          email: email
          // Whatever more...
       });
}

#8

Brilliant, thanks, I’ll give this a shot Monday morning.

Edit:

@thomasyajl36 Worked a treat btw - thanks!!