Next.js: False positive report of "API resolved without sending a response"

Created on 6 Feb 2020  路  23Comments  路  Source: vercel/next.js

Bug report

Describe the bug

_Api endpoint_

Next will log the "API resolved without sending a response" warning even though the API endpoint always send a response back.

To Reproduce

Here the code that triggers the warning:

export default async function(req: NextApiRequest, res: NextApiResponse) {
  switch (req.method) {
    case "POST":
    case "OPTION": {
      try {
        const request = http.request( // Node core http module
          url,
          {
            headers: await makeHeaders(req, res),
            method: req.method,
          },
          response => {
            response.pipe(res);
          },
        );

        request.write(JSON.stringify(req.body));

        return request.end();
      } catch (error) {
        Log.error(error); // Can be a simple console.error too
      }

      return res.status(500).end();
    }
  }

  return res.status(405).end();
}

It seems that this endpoint will always send a response back.

Expected behavior

No warning

System information

  • OS: MacOS
  • Version of Next.js: 9.2.1

Most helpful comment

@gaku-sei it is most likely caused by the callback as we can't detect you are still doing work in the API unless you return a promise and wait to resolve it until after the callback is fired e.g.

export default async function(req: NextApiRequest, res: NextApiResponse) {
  return new Promise(resolve => {
    switch (req.method) {
      case "POST":
      case "OPTION": {
        try {
          const request = http.request( // Node core http module
            url,
            {
              headers: await makeHeaders(req, res),
              method: req.method,
            },
            response => {
              response.pipe(res);
              resolve()
            },
          );

          request.write(JSON.stringify(req.body));
          request.end();
        } catch (error) {
          Log.error(error); // Can be a simple console.error too
          res.status(500).end();
          return resolve()
        }
      }
    }
    res.status(405).end();
    return resolve()
  })
}

All 23 comments

This has been fixed in canary, can you try next@canary?

same issue here, i tried next@canary Next still logs "API resolved without sending a response"

@iddify please provide code instead of saying "same issue", it's unlikely that you're doing 100% exactly the same as the person that posts an issue.

@timneutkens I'm simply trying to Integrate sendgrid to handle a form via this endpoint '/api/bulk-order'

  • bulk-order.js
const sgMail = require('@sendgrid/mail');

sgMail.setApiKey(process.env.SENDGRID_APIKEY);

export default function handler(req, res) {
  ///const { name, email, phone, date, order_desc } = req.body;
  const msg = {
    to: '[email protected]',
    from: '[email protected]',
    subject: 'Sending with Twilio SendGrid is Fun',
    text: 'and easy to do anywhere, even with Node.js',
    html: '<strong>and easy to do anywhere, even with Node.js</strong>'
  };
  sgMail.send(msg);
}
  • Form.js
const sendEmail = (url, emailData) => {
  fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(emailData)
  });
};
const handleSubmitForm = () => {
    sendEmail('/api/bulk-order', emailBody);
};

when i submit nothing really happens other the the console logs "API resolved without sending a response for /api/bulk-order, this may result in a stalled requests."

UPDATE: i wasn't resolving the request, returning a 200 status code after the request finished removed the warning for me, MY BAD!

@timneutkens Thank you for the quick reply. Unfortunately 9.2.2-canary.12 doesn't solve the issue 馃槥

I don't know exactly how Next analyzes whether or not a route actually returns something, but it could be because of the callback in http.request or the try/catch ?

I also wonder if this couldn't be because of the http.request function that could "silently" fail and just not do anything 馃

I will investigate a bit more 馃憤

@gaku-sei it is most likely caused by the callback as we can't detect you are still doing work in the API unless you return a promise and wait to resolve it until after the callback is fired e.g.

export default async function(req: NextApiRequest, res: NextApiResponse) {
  return new Promise(resolve => {
    switch (req.method) {
      case "POST":
      case "OPTION": {
        try {
          const request = http.request( // Node core http module
            url,
            {
              headers: await makeHeaders(req, res),
              method: req.method,
            },
            response => {
              response.pipe(res);
              resolve()
            },
          );

          request.write(JSON.stringify(req.body));
          request.end();
        } catch (error) {
          Log.error(error); // Can be a simple console.error too
          res.status(500).end();
          return resolve()
        }
      }
    }
    res.status(405).end();
    return resolve()
  })
}

@ijjk Thank you very much, that worked perfectly for me!

Issue solved 馃槃

I see the same warning with apollo-server-express.

@danielhusar Any idea what could be the valid solution for apollo-server-express? Hitting the same issue "API resolved without sending a response for /, this may result in stalled requests.".
/ is not even called in my app, my endpoint is /api/graphql.

I havent been able to figure it out yet. Im considering to switch to express server to handle all requests. (Instead of just api)

We're going to add a config option to opt-out of the warning for certain api routes if you're sure they resolve

I'm still running into this:

export default async function token(req, res) {
  try {
    const { user } = await auth0.getSession(req);

    if (user) {
      return new Promise((resolve, reject) => {
        fetch(`https://${process.env.domain}/oauth/token`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            grant_type: 'client_credentials',
            client_id: process.env.authClientID,
            client_secret: process.env.authClientSecret,
            audience: `https://${process.env.domain}/api/v2/`,
          }),
        })
        .then((res) => res.json())
        .then(({ access_token, scope, expires_in, token_type }) => {
          token = { access_token, scope, expires_in, token_type };
          console.log(token)
          resolve(token);
        })
        .catch(err => {
          reject(err);
        })
      })
    }
    else {
      throw new Error('No User');
    }
  } catch (error) {
    console.error(error)
    res.status(error.status || 500).end(error.message)
  }
}
export default async function token(req, res) {
  try {
    const { user } = await auth0.getSession(req);

    if(!user) {
      throw new Error('No User');
    }

    const result = await fetch(`https://${process.env.domain}/oauth/token`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        grant_type: 'client_credentials',
        client_id: process.env.authClientID,
        client_secret: process.env.authClientSecret,
        audience: `https://${process.env.domain}/api/v2/`,
      }),
    })
    const { access_token, scope, expires_in, token_type } = await result.json()


    return { access_token, scope, expires_in, token_type }
  } catch (error) {
    console.error(error)
    return res.status(error.status || 500).end(error.message)
  }
}

This should solve your case, but you can now disable the warning also: https://nextjs.org/docs/api-routes/api-middlewares

// export this from the api route
export const config = {
  api: {
    externalResolver: true,
  },
}

I'm not sure I understand. I'm getting it with this code which I got from the example for firebase server authentication:

pages/api/login.ts:

import commonMiddleware from '../../middleware/commonMiddeware';
import { verifyIdToken } from '../../firebase/auth/admin';

const handler = async (req, res) => {
  if (!req.body) {
    return res.status(400);
  }

  const { token } = req.body;

  try {
    const decodedToken = await verifyIdToken(token);
    req.session.decodedToken = decodedToken;
    req.session.token = token;
    return res.status(200).json({ status: true, decodedToken });
  } catch (error) {
    return res.status(500).json({ error });
  }
};

export default commonMiddleware(handler);

Looks like you're not finishing the request when a body is not set:

  if (!req.body) {
    return res.status(400);
  }

Should be:

  if (!req.body) {
    return res.status(400).send({});
  }

Looks like you're not finishing the request when a body is not set:

  if (!req.body) {
    return res.status(400);
  }

Should be:

  if (!req.body) {
    return res.status(400).send({});
  }

Have the same problem and the above fix isn't working for me. :/

I have the same problem. The message just a warning or can it really give you problems?

I'm having the same problem. Why is this issue closed? Is this a problem from Next server or am I doing something wrong?

+1 same for me

I am getting this same warning too however I am getting the data I expect to revieve in the console :/

Updated to next@canary and I'm still seeing this error.

here's my handler:

const trades = mongoMiddleware(async (req, res, connection, models) => {
  const {
    method
  } = req

  apiHandler(res, method, {
    GET: (response) => {
      models.Trade.find({}, (error, trade) => {
        if (error) {
          connection.close();
          response.status(500).json({ error });
        } else {
          response.status(200).json(trade);
          connection.close();
        }
      })
    }
  });
})

When I hit my route I get a json array returned with all the trades.. but I get this in the console:

API resolved without sending a response for /api/trades, this may result in stalled requests.

People still running into this issue might want to look closely at: https://github.com/vercel/next.js/issues/10439#issuecomment-633013628 and https://github.com/vercel/next.js/pull/11380

If you're using an externalResolver (such as Express), nextjs can't detect that the API response has been send. At the bottom of https://github.com/vercel/next.js/issues/10439#issuecomment-633013628 @timneutkens explains how you can disable the warning if that is indeed the case.

Was this page helpful?
0 / 5 - 0 ratings