Search code examples
javascriptnode.jsnext.jsgraphqlapollo

Next JS ERR_HTTP_HEADERS_SENT error after GraphQL mutation fails


So I'm using Next JS API routes and in one of such routes I'm calling a GraphQL mutation using Apollo, something like:

// pages/api/foo.js

import { initializeApollo } from '~/server/apollo'

export default function handler(req, res) {
  const client = initializeApollo()
  try {
    await client.mutate({ mutation: FooDocument })
    // this works
    res.status(200).send({ foo: '...' })
  } catch {
    // this fails
    res.status(500).send({ error: '...' })
  }
}

as you can see if the mutation fails I get a server error when calling res.status(500).send({ error: '...' }):

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

But If the mutation succeeds I got no error when calling res.status(200).send({ foo: '...' }).

Does anyone knows why this happens? I guess that my best alternative is to call this mutation only in the frontend but I would like to know if there's a way around this.


Solution

  • Oh I see, I had a redirect in the errorLink of the ApolloClient configuration, it was hard to spot because this code was in a different file:

    const errorLink = onError(({ graphQLErrors }) => {
      graphQLErrors.forEach(error => {
        if (err.message === 'foo') {
           // this redirect was the problem
           ctx.res.writeHead(307, { Location: '/somewhere' })
        }
      })
    })
    

    and so the errorLink was catching the error I was checking out and it was trying to do a redirect, that redirect was setting the headers and it was being ignored since I'm using the API routes. To solve this I just did an early return for that specific operation:

    const errorLink = onError(({ graphQLErrors, operation }) => {
      if (operation.operationName === 'MyMutation') {
        return
      }
    
      graphQLErrors.forEach(/*...*/);
    })