gatsbyjs/gatsby · critical

UNHANDLED REJECTION

Error message

UNHANDLED REJECTION

What it means

Top-level `process.on('unhandledRejection', ...)` handler installed by the gatsby CLI. Any Promise rejection that nothing else `.catch`es reaches here; the handler wraps non-Error reasons into Errors and calls `report.panic`, which logs structured output and exits nonzero. The message is a generic label; the real cause is the wrapped `reason`.

Source

Thrown at packages/gatsby-cli/src/index.ts:69

//     report.stripIndent(`
//       Node.js ${version} has reached End of Life status on 31 December, 2019.
//       Gatsby will only actively support ${NEXT_MIN_NODE_VERSION} or higher and drop support for Node 8 soon.
//       Please upgrade Node.js to a currently active LTS release: https://gatsby.dev/upgrading-node-js
//     `)
//   )
// }

process.on(`unhandledRejection`, reason => {
  // This will exit the process in newer Node anyway so lets be consistent
  // across versions and crash

  // reason can be anything, it can be a message, an object, ANYTHING!
  // we convert it to an error object so we don't crash on structured error validation
  if (!(reason instanceof Error)) {
    reason = new Error(util.format(reason))
  }

  report.panic(`UNHANDLED REJECTION`, reason as Error)
})

process.on(`uncaughtException`, error => {
  report.panic(`UNHANDLED EXCEPTION`, error)
})

createCli(process.argv)

View on GitHub (pinned to 8b06340921)

Solutions

  1. Read the wrapped `reason`/stack in the panic output to locate the rejecting code.
  2. Add `.catch()` or wrap the `await` in try/catch at the call site identified by the stack.
  3. Ensure all async lifecycle exports (`createPages`, etc.) fully await their promises.
  4. Update plugins/themes whose unhandled rejections are the source.

Example fix

// before: unawaited rejection
exports.createPages = ({ graphql }) => {
  graphql(`{ ... }`).then(d => buildPages(d))  // rejection unhandled
}

// after
exports.createPages = async ({ graphql, reporter }) => {
  try {
    const { data } = await graphql(`{ ... }`)
    buildPages(data)
  } catch (e) { reporter.error('createPages failed', e) }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure all async lifecycle exports await and catch
async function safeRun(fn) { try { await fn() } catch (e) { reporter.error(e) } }

Try / catch

process.on('unhandledRejection', (reason) => {
  const err = reason instanceof Error ? reason : new Error(String(reason))
  reporter.panic('UNHANDLED REJECTION', err)
})

Prevention

When it happens

Trigger: An async operation anywhere in the gatsby process rejects and no `.catch()`/`try-await` handles it. Examples: an unawaited `graphql()` call in `gatsby-node`, a plugin's async hook that throws, a fetch/filesystem rejection during build.

Common situations: Plugin or theme bug surfacing an unhandled rejection; `gatsby-node`/`gatsby-config` async code missing await or try/catch; Node version differences where unhandled rejections abort by default; network errors in user code called from lifecycle hooks.

Related errors


AI-assisted analysis of gatsbyjs/gatsby@8b06340921 (2026-08-13). Data as JSON: /api/errors/59aea3828c1143ff. Report an issue: GitHub.