Apollo 3, Meteor and “Cannot await without a Fiber”

I apologise for asking this question here, but I’m having no luck on the Meteor forums or on Stack Overflow, and you probably have a much better chance of understanding which Apollo 3 changes are causing my issue, especially since at least some Apollo devs will presumably still remember their Meteor days :wink:

I’m been struggling for days now to update my Meteor app to use Apollo 3. I’m blocked on a very frustrating problem every time a resolver accesses Mongo:

"stacktrace": [
  "AssertionError [ERR_ASSERTION] [ERR_ASSERTION]: Cannot await without a Fiber",
  "    at awaitPromise (/Users/Tim/.meteor/packages/promise/.0.12.0.acrhc3.4u34++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/promise_server.js:75:12)",
  "    at Promise.await (/Users/Tim/.meteor/packages/promise/.0.12.0.acrhc3.4u34++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/promise_server.js:60:12)",
  "    at SynchronousCursor._nextObject (packages/mongo/mongo_driver.js:1118:38)",
  "    at SynchronousCursor.forEach (packages/mongo/mongo_driver.js:1132:22)",
  "    at SynchronousCursor.map (packages/mongo/mongo_driver.js:1142:10)",
  "    at SynchronousCursor.fetch (packages/mongo/mongo_driver.js:1166:17)",
  "    at Cursor.<computed> [as fetch] (packages/mongo/mongo_driver.js:920:44)",
  "    at MongoConnection.findOne (packages/mongo/mongo_driver.js:827:56)",
  "    at Collection.findOne (packages/mongo/collection.js:358:29)",
  "    at loginWithToken (app/api/auth/server/resolvers/mutation/login-with-token.ts:16:16)",

I have tried everything that I can think of, including:

Wrapping the apollo-server-express middleware inside Meteor.bindEnvironment before attaching it to the connect handler

Wrapping every resolver function inside Meteor.bindEnvironment before calling makeExecutableSchema.

I’m out of ideas. If I downgrade to Apollo Server 2.25.2 keeping all the rest of the code the same it works perfectly.

Hey @tarmes! Sorry for the trouble.

Have you followed the AS3 migration guide closely? There are some breaking changes that may require updating your config.

I’m no Meteor expert but I can rope one in if need be (or lean on some history). It looks like the nature of this error is related to some async code, specifically trying to await something that wasn’t previously async but now is expected to be. While this is fine in normal JS, I don’t know much about Fibers so maybe there’s something there. Relating to AS3, I’m immediately drawn to the fact that almost all plugin hooks should now be implemented as async. For the specifics on this, check this section out and verify you’ve made the necessary updates.

Hope this helps! If it doesn’t, let me know and we can do some more digging.

Hi,

Yes I have followed it closely, and I’m not using any plugins.

Ok. Plugins would have been my best guess.

I spent a little time looking to see if this is reproducible in the simplest of cases, and it is. The steps I took to create a reproduction were:

meteor create apollo-app --apollo
meteor npm install apollo-server-express@latest
meteor npm install express@4
meteor

Navigate to http://localhost:3000/graphql and issue a simple query:

query {
  getLinks {
    _id
  }
}

I got the error you’re seeing:

Expand for error

{
“errors”: [
{
“message”: “Cannot await without a Fiber”,
“locations”: [
{
“line”: 2,
“column”: 3
}
],
“path”: [
“getLinks”
],
“extensions”: {
“code”: “INTERNAL_SERVER_ERROR”,
“exception”: {
“generatedMessage”: false,
“code”: “ERR_ASSERTION”,
“actual”: false,
“expected”: true,
“operator”: “==”,
“stacktrace”: [
“AssertionError [ERR_ASSERTION] [ERR_ASSERTION]: Cannot await without a Fiber”,
" at awaitPromise (/Users/trevorscheer/.meteor/packages/promise/.0.12.0.qsgjpe.bwik++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/promise_server.js:75:12)",
" at Promise.await (/Users/trevorscheer/.meteor/packages/promise/.0.12.0.qsgjpe.bwik++os+web.browser+web.browser.legacy+web.cordova/npm/node_modules/meteor-promise/promise_server.js:60:12)",
" at SynchronousCursor._nextObject (packages/mongo/mongo_driver.js:1118:38)",
" at SynchronousCursor.forEach (packages/mongo/mongo_driver.js:1132:22)",
" at SynchronousCursor.map (packages/mongo/mongo_driver.js:1142:10)",
" at SynchronousCursor.fetch (packages/mongo/mongo_driver.js:1166:17)",
" at Cursor. [as fetch] (packages/mongo/mongo_driver.js:920:44)",
" at getLinks (server/apollo.js:10:44)",
" at field.resolve (/Users/trevorscheer/Desktop/apollo-app/node_modules/apollo-server-core/dist/utils/schemaInstrumentation.js:52:26)",
" at resolveField (/Users/trevorscheer/Desktop/apollo-app/node_modules/graphql/execution/execute.js:464:18)",
" at executeFields (/Users/trevorscheer/Desktop/apollo-app/node_modules/graphql/execution/execute.js:292:18)",
" at executeOperation (/Users/trevorscheer/Desktop/apollo-app/node_modules/graphql/execution/execute.js:236:122)",
" at executeImpl (/Users/trevorscheer/Desktop/apollo-app/node_modules/graphql/execution/execute.js:116:14)",
" at Object.execute (/Users/trevorscheer/Desktop/apollo-app/node_modules/graphql/execution/execute.js:60:35)",
" at execute (/Users/trevorscheer/Desktop/apollo-app/node_modules/apollo-server-core/dist/requestPipeline.js:205:36)",
" at Object.processGraphQLRequest (/Users/trevorscheer/Desktop/apollo-app/node_modules/apollo-server-core/dist/requestPipeline.js:139:34)"
]
}
}
}
],
“data”: {
“getLinks”: null
}
}

This is pretty out of my wheelhouse, but hopefully this reproduction is useful to you or someone else. I’ll share this with others here and see if anyone is able to help.

1 Like

@tarmes I’ve opened an issue for this. I’d really appreciate and encourage your participation there if you can spare the effort!

2 Likes

Meteor skeleton has been updated for Apollo 3 in the upcoming Meteor 2.4 release. If you want to try it out give the beta a try. Prior to Meteor 2.4 the skeleton uses Apollo 2, so if you want to use the latest Apollo you need to make the necessary upgrades.

These should be:
All resolvers and queries should be async functions.

const resolvers = {
  Query: {
    getLink: async (obj, { id }) => LinksCollection.findOne(id),
    getLinks: async () => LinksCollection.find().fetch()
  }
};

Add express as a dependency to your app.

Change your server Apollo start to:

// apollo.js
import { ApolloServer } from 'apollo-server-express';
import { WebApp } from 'meteor/webapp';
import { getUser } from 'meteor/apollo';
import { makeExecutableSchema } from '@graphql-tools/schema';

const server = new ApolloServer({
  schema: makeExecutableSchema({
    typeDefs,
    resolvers,
  }),
  context: async ({ req }) => ({
    user: await getUser(req.headers.authorization)
  })
})

export async function startApolloServer() {
  await server.start();
  const app = WebApp.connectHandlers;

  server.applyMiddleware({
    app,
    cors: true
  });
}

// main.js
import { startApolloServer } from './apollo';

function insertLink({ title, url }) {
  LinksCollection.insert({title, url, createdAt: new Date()});
}

try {
  startApolloServer().then();
} catch (e) {
  console.error(e.reason);
}
4 Likes

Thank you @Storyteller! :tada:

Thanks @Storyteller. I’ll try this when I get back from my weeks vacation, although I’m pretty sure that I’ve already done all that.

Hi,

Just to let you know that I effectively had to make all my resolvers async, and it now works. Thanks!