Catching meteor publish errors

I’m discovering some really awkward functionality where errors in Meteor.publish are not being discovered in the logs either on the client or the server. In the leaderboard app, I’ve been testing some things out. Apparently, you have to use this.error instead of Meteor.Error in a publish function which seems really odd. So I’m trying to catch any errors and then throw them with this.error so I can see them somwhere, but this still isnt working:

  Meteor.publish('players', function() {
    try {
      throw new Meteor.Error('123', 'hey!')
    } catch (e) {
      console.log("here", e)
      this.error(e)
    }
    return Players.find()
  })

any ideas?

The documentation for Meteor.Error is a little confusing, but if read along with the documentation for the error method in a publication, it becomes a little clearer.

My understanding is that throwing a Meteor.Error is a technique for getting that error sent over DDP to the client - it does not affect exception handling on the server.

So, throwing a Meteor.Error and trying to catch it in a publish isn’t going to do anything for you - you need to use standard JavaScript error handling if this is to happen on the server.

Meteor.publish('players', function() {
    try {
      throw ('123')
    } catch (e) {
      console.log("here", e) // we log the standard JS error
      this.error(new Meteor.Error(e, 'hey!')) // and then coerce it into a Meteor error for the client
    }
    return Players.find()
  })

(You may not need the coercion - the docs imply that it will be appropriately sanitized).

1 Like

Well my problem is that when I do this:

  Meteor.publish('players', function() {
    throw new Meteor.Error('123', 'hey!')
    return Players.find()
  })

I don’t see any errors in the client or server console.

That’s because you’re throwing a meteor error on the server side and not catching it!
Rob is passing the meteor error to the client and then handling any server side errors using the try { } catch { }.

Your code never runs the return because it’s throwing a uncaught error in the first line.

1 Like

Ahhh

Throwing the Meteor.Error does get caught and I can log it, but it doesnt end up on the client in the snippet I provided

Then consider it your research task to find out how to log it on the client. Come on, I think we’ve given enough hints, your turn! :slight_smile:

@mordrax, I did this. I created a leaderboard app, removed autopublish, added Meteor.subscribe('players') on the client and not he server, I added:

  Meteor.publish('players', function() {
    try {
      throw new Meteor.Error('123', 'hey!')
    } catch (e) {
      console.log("here", e)
      this.error(e)
    }
    return Players.find()
  })

And I didn’t see anything on the client.

I suppose the docs say it just calls onStop. But I think its really odd that no errors are thrown on the client on the server. Everything is just hidden

you mean on the client from the server? What does your client code looks like? This won’t throw an error on the client, it’ll just hit the onError callback and in there your console.log code should execute. I haven’t done it before, perhaps @robfallows can weigh in?

Ok. Just try this:

meteor create --example leaderboard
cd leaderboard
meteor remove autopublish

Then in leaderboard.js client add:

Meteor.subscribe('players')

and on the server:

 Meteor.publish('players', function() {
    try {
      throw new Meteor.Error('123', 'hey!')
    } catch (e) {
      this.error(e)
    }
    return Players.find()
  })

You’ll see nothing on the client or the server. Or try this:

 Meteor.publish('players', function() {
    throw new Meteor.Error('123', 'hey!')
    return Players.find()
  })

and still nothing. I don’t get it. It seems like a terrible default functionality. It took me a while to figure out that my publish functions were broken…

Here ya go minimal working version, check your debug console. Took me a few goes to get right, confused about the callback object and forgot to capitalise the e in Meteor.error :stuck_out_tongue:

ahh. That such a pain in the ass. Why aren’t these errors just thrown by default? It seems ridiculous that I’d have to make a wrapper function like this for all my publictions and subscriptions:

publish = function(name, func) {
  Meteor.publish(name, function() {
    try {
      return func.apply(this, arguments)
    } catch(e) {
      this.error(e)
    }
  })
}

subscribe = function() {
  args = arguments.concat([{
    onError: function (e) {
      throw e
    }
  }])
  Meteor.subscribe.apply(Meteor, args)
}

publish('players', function() {
  throw new Meteor.Error(1234, 'uh oh')
})

subscribe('players')

I guess because what you’re talking about is meteor being opinionated about error propagation and always broadcasting all server uncaught errors to the client.

Both of which should be left in the developer’s control. The second is especially dangerous because it will send any errors thrown below your code (in the call stack) to the client.

I would suggest you catch the error, log it and then return a generic formatted text for the client. e.g your error could be ERROR: The secret key 'AKL2342nSADFWER23' does not match. And you would return a new Meteor.Error('PubNameFailed', 'Something went very wrong with the server. Please refresh the page and try again.')

2 Likes

interesting… fair point