UnhandledPromiseRejectionWarning: Error: You must `await server.start()` before calling `server.applyMiddleware()` at ApolloServer

Error HandlingServerGraphqlNestjsApollo

Error Handling Problem Overview


I am trying to start my nestJs server and It keeps giving me this error:

UnhandledPromiseRejectionWarning: Error: You must await server.start() before calling server.applyMiddleware() at ApolloServer

I'm not even sure where to debug from as I am still very new at NestJs and GraphQL.

Error Handling Solutions


Solution 1 - Error Handling

This is a known bug with an open issue and a merged PR to fix it. For now, you can downgrade to apollo-server-express@^2

Solution 2 - Error Handling

A complete working code is:

const express = require("express");
const { ApolloServer } = require("apollo-server-express");
const http = require("http");

const app = express();

const typeDefs = `
	type Query{
		totalPosts: Int!
	}
`;
const resolvers = {
	Query: {
		totalPosts: () => 100,
	},
};
let apolloServer = null;
async function startServer() {
	apolloServer = new ApolloServer({
		typeDefs,
		resolvers,
	});
	await apolloServer.start();
	apolloServer.applyMiddleware({ app });
}
startServer();
const httpserver = http.createServer(app);

app.get("/rest", function (req, res) {
	res.json({ data: "api working" });
});

app.listen(4000, function () {
	console.log(`server running on port 4000`);
	console.log(`gql path is ${apolloServer.graphqlPath}`);
});

Solution 3 - Error Handling

I faced this issue when upgrading Ben Awad's Graphql-Next-Typeorm[...] stack, simply adding an await to server start fixed the warnings

const apolloServer = new ApolloServer({
    introspection: true,
    schema: await buildSchema({
      resolvers: [__dirname + '/resolvers/**/*.js'],
      validate: false
    }),
    context: ({ req, res }) => ({
      req,
      res,
      redis: redisClient
    }),
    formatError
  });


// added this line
  await apolloServer.start();

  apolloServer.applyMiddleware({
    app,
    cors: false
  });

Solution 4 - Error Handling

For Apollo Server Express 3.0 and above, you need to define an async function that takes in typeDefs and resolvers parameters, then assign the server to the same Apollo initialization as before as shown here

async function startApolloServer(typeDefs, resolvers){
    const server = new ApolloServer({typeDefs, resolvers})
    const app = express();
    await server.start();
    server.applyMiddleware({app, path: '/graphql'});
    
    app.listen(PORT, () => {
    console.log(`Server is listening on port ${PORT}${server.graphqlPath}`);
})
}

startApolloServer(typeDefs, resolvers);

Solution 5 - Error Handling

You can put everything in an async function and execute the function in your server(app,index...).js. You may also check the npm package. https://www.npmjs.com/package/apollo-server-express For example:

const express = require('express')
    , http = require('http')
    , path = require('path');
const { ApolloServer } = require('apollo-server-express');

async function startExpressApolloServer() {

    const { typeDefs } = require('./graphql/schemas/schema');
    const { resolvers } = require('./graphql/resolvers/resolver');

    const server = new ApolloServer({ typeDefs, resolvers });
    await server.start();

    const app = express();
    
    server.applyMiddleware({ app, path: '/api/graphql' });

    await new Promise(resolve => app.listen({ port: 3001 }, resolve));
    console.log(`Server ready at http://localhost:3001${server.graphqlPath}`);
    return { server, app };
}

startExpressApolloServer();

Solution 6 - Error Handling

downgrading is not the option (at least anymore)

here is the solution =>

https://javascriptsu.wordpress.com/2021/08/02/apollo-error-must-await-server-start/

const server = new ApolloServer({ typeDefs, resolvers });
const app = express();

server.start().then(res => {
 server.applyMiddleware({ app });
 app.listen({ port: 3000 }, () =>
   console.log("nice")
 )
})

Solution 7 - Error Handling

I had the same type of problem. I was using TypeScript, Express, ApolloServer. What I did-

async function a(){
  const server = new ApolloServer({ typeDefs, resolvers });
  await server.start();
  server.applyMiddleware({ app, path: '/graphql' });
}
a();

Solution 8 - Error Handling

One other option is to downgrade your apollo to any 2.x.x. It solved my problem

Solution 9 - Error Handling

This is not a bug. As per the documentation, the Apollo server needs to be instantiated in an async function. This is the recommended setup for Apollo Express:

import { ApolloServer } from 'apollo-server-express';
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core';
import express from 'express';
import http from 'http';

async function startApolloServer(typeDefs, resolvers) {
  const app = express();
  const httpServer = http.createServer(app);
  const server = new ApolloServer({
    typeDefs,
    resolvers,
    plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
  });
  await server.start();
  server.applyMiddleware({ app });
  await new Promise(resolve => httpServer.listen({ port: 4000 }, resolve));
  console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`);
}

Solution 10 - Error Handling

In v3, if you use apollo-server-express the start function is required https://www.apollographql.com/docs/apollo-server/api/apollo-server/#start.

You can do something like this.

const app = express()
app.use(express.urlencoded({ extended: true }))
app.use(express.json())
....
export const startup = async () => {
  await server.start()
  server.applyMiddleware({ app, path: `/api/${configs.region}/graphql` })
  return app
}

// call startup in another file to get app

Solution 11 - Error Handling

It is not ok to start the apollo server in advance. What happens with the case when I have to explicitly use http/https. Please see the following case:

  const server = new ApolloServer({
    typeDefs: [KeycloakTypeDefs, typeDefs], // 1. Add the Keycloak Type Defs
    schemaDirectives: KeycloakSchemaDirectives, // 2. Add the
    formatError: new ApolloErrorConverter(),
    resolvers: resolvers,
    context: ({ req }) => {
      return makeContextWithDependencies(req);
    }
  });
  server.applyMiddleware({ app });

  http.createServer(app).listen(config.server.port, os.hostname());
  const options = {
    key: fs.readFileSync(config.server.ssl.keyFile, "utf8"),
    cert: fs.readFileSync(config.server.ssl.certFile, "utf8"),
    passphrase: config.server.ssl.passphrase
  };
  https
    .createServer(options, app)
    .listen(config.server.securePort, os.hostname());
  console.log(
    "Server waiting for requests on ports: " +
      config.server.port +
      "," +
      config.server.securePort
  );

Solution 12 - Error Handling

There are already some great answers here. But we should know why and where we should call server.start(). From apollo docs -

> Always call await server.start() before calling > server.applyMiddleware and starting your HTTP server. This allows > you to react to Apollo Server startup failures by crashing your > process instead of starting to serve traffic.

Solution 13 - Error Handling

We must wait for the server to get ready before adding middleware to it.

    const app = express();
    const apolloServer = new ApolloServer({
        schema: await buildSchema({
            resolvers: [HelloResolver],
            validate: false,
        }),
    });
    
    await apolloServer.start(); // First start the server then apply middleware on it

    apolloServer.applyMiddleware({ app });

Solution 14 - Error Handling

you can do like that, it works for me.

const server = new ApolloServer({ schema });
const startApollo = async () => {
  try {
    await server.start();
    server.applyMiddleware({ app, path: "/api"})
  } catch (error) {
    console.log(error);
  }
}

Solution 15 - Error Handling

This is my working server:

import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import typeDefs from './schema';

const app = express();

const server = new ApolloServer({
  typeDefs,
  mocks: true
});

server.start().then(() => {
  server.applyMiddleware({
    app,
    cors: true,
  });
});

const PORT = 4000;

app.listen(PORT, () => {
  console.log(
    `GraphQL endpoint and playground accessible at http://localhost:${PORT}${server.graphqlPath}`,
  );
});
  

The key thing here is to wrap the "applyMiddleware" function call inside the "server.start" async function.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBoladekView Question on Stackoverflow
Solution 1 - Error HandlingJay McDonielView Answer on Stackoverflow
Solution 2 - Error Handlinguser1388835View Answer on Stackoverflow
Solution 3 - Error HandlingeliastouilView Answer on Stackoverflow
Solution 4 - Error HandlingpnoknView Answer on Stackoverflow
Solution 5 - Error HandlingOguzView Answer on Stackoverflow
Solution 6 - Error HandlinglukaView Answer on Stackoverflow
Solution 7 - Error HandlingMahedi KamalView Answer on Stackoverflow
Solution 8 - Error HandlingHakim MarleyView Answer on Stackoverflow
Solution 9 - Error HandlingOamar KanjiView Answer on Stackoverflow
Solution 10 - Error HandlingTony NguyenView Answer on Stackoverflow
Solution 11 - Error HandlingCiprian PascuView Answer on Stackoverflow
Solution 12 - Error HandlingMI SabicView Answer on Stackoverflow
Solution 13 - Error HandlingSumit BopcheView Answer on Stackoverflow
Solution 14 - Error HandlingYahya UnluView Answer on Stackoverflow
Solution 15 - Error HandlingDavid GabrielyanView Answer on Stackoverflow