Skip to content
← Back to activity

Immutable solution version

Diagnose and fix Netlify build failures: classify the failing stage first

Version 2

Complete solution

Shows how to fix diagnose and fix Netlify build failures: classify the failing stage first. Use it when you hit this exact problem. Skip it when your error message or symptom looks different.

TL;DR

For "Failed during stage "building site": Build script returned non-zero exit code: 2": the single most useful line in the deploy log is the stage marker, because each stage fails for different reasons: ` Failed during stage "building site": Build script returned non-zero exit code: 2 ` The base directory is where Netlify looks for package.json /.nvmrc, installs dependencies, and runs the build command. Fix: set base to the real subdirectory. Then recheck publish: it is resolved relative to the base directory, not the repo root.

Failed during stage "building site": Build script returned non-zero exit code: 2

When to use

You are seeing this: Open the deploy log and find the Failed during stage "..." line. - "building site", your build command (or its environment) failed. Use this skill when you run into "Diagnose and fix Netlify build failures: classify the failing stage first".

When not to use

If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.

Versions

No specific versions are mentioned in the source material, so treat the fix as generally applicable and check the examples against whatever you have installed.

Use this when a Netlify deploy fails during the build. The single most useful line in the deploy log is the stage marker, because each stage fails for different reasons:

Failed during stage "building site": Build script returned non-zero exit code: 2

1. Find which stage failed

Open the deploy log and find the Failed during stage "..." line.

  • "building site", your build command (or its environment) failed. Everything in section 2 applies.

  • "deploying site", the build succeeded but deploy-time processing failed (oversized function bundles, form/redirect processing). See the functions skill for bundle-size issues.

  • Earlier stages ("preparing repo", "initializing"), the problem is upstream of your code: a bad base directory, missing repo access, or invalid config. Read the lines immediately above the failure.

2. Classify by the error signature

Match the log's distinctive text to one of these before you touch config.

A. "Base directory does not exist" or a missing publish directory

Base directory does not exist: /opt/build/repo/web

Cause: the base directory in build settings doesn't match a directory in the repo. The base directory is where Netlify looks for package.json / .nvmrc, installs dependencies, and runs the build command.

Fix: set base to the real subdirectory. Then recheck publish: it is resolved relative to the base directory, not the repo root. The classic double-up: base web plus publish web/public makes Netlify look for /opt/build/repo/web/web/public. With base web, publish should be just public.

B. JavaScript heap out of memory, or "Killed"

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
10:14:05 AM: /opt/build-bin/build: line 77:  1351 Killed [... details about the build]

Cause: the build tried to allocate more memory than the build container has. Gatsby builds hit this most often; anything bundling a huge dependency tree can too. This is an infrastructure limit, not a bug in your code.

Fix: raise Node's old-space heap via a NODE_OPTIONS environment variable. Per the Netlify support guide, --max-old-space-size=4096 is a common value that works, set it in site settings under Environment variables, or in netlify.toml:

[build.environment]
  NODE_OPTIONS = "--max-old-space-size=4096"

Also: reduce parallel workers (parallel webpack/Gatsby workers multiply memory contention without helping on a small build container), and if the site is simply huge, Netlify's High-Performance Builds is the paid escape hatch.

C. Your build command exited non-zero

Failed during stage "building site": Build script returned non-zero exit code: 2

Cause: your command failed. Scroll up for your tool's error, the stage line is only the summary. Two Netlify-specific traps to check first:

  1. CI is set. Netlify runs builds with CI=true (the log shows $ CI= npm run build). Some frameworks treat warnings as errors under CI react-scripts build (create-react-app) is the classic case: warnings that pass locally fail the Netlify build. Either fix the warnings or override the behavior in build settings.

  2. Node version mismatch. Engines incompatibility, or syntax errors on code that runs fine locally, means the build used the wrong Node. Pin it with a NODE_VERSION variable (or a .nvmrc file, or package.json engines):

[build.environment]
  NODE_VERSION = "20"

D. Environment variable missing at build time

Symptoms: ReferenceError: SOME_VAR is not defined, or API calls returning 401/404 during the build.

Causes, in order of likelihood:

  1. The variable was added or changed after the last deploy, env vars are baked in at build time, so you must trigger a new deploy.

  2. Wrong deploy-context scoping: works on production but fails on deploy previews (or vice versa), check which contexts the variable is enabled for.

  3. A NETLIFY_-prefixed name, that prefix is reserved and the UI rejects it (except NETLIFY_AUTH_TOKEN / NETLIFY_SITE_ID, which are CLI-local, not site variables).

3. The build config reference

The real keys in netlify.toml:

[build]
  command = "npm run build"        # build command
  publish = "dist"                 # output dir, relative to base
  base = ""                        # repo subdirectory to build from
  functions = "netlify/functions"  # serverless function sources
  edge_functions = "netlify/edge-functions"
  ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF -- src/"

[build.environment]
  NODE_VERSION = "20"

[context.deploy-preview]
  command = "npm run build:preview"  # per-context overrides

One rule that bites people: settings in netlify.toml override the same settings in the Netlify UI. If a value lives in both places, the file wins keep it in one place.

To reproduce the build locally in the same environment, run netlify build (Netlify CLI) from the repo root.

4. Checklist

  1. Read the Failed during stage line first, only then scroll up for the real error.
  2. Base/publish: Base directory does not exist → fix base; then fix publish (relative to base, not repo root).

  3. OOM / Killed → NODE_OPTIONS with --max-old-space-size=4096; reduce parallelism.
  4. Non-zero exit → find your tool's error; check the CI= warnings-as-errors trap; pin NODE_VERSION.

  5. Missing env var → redeploy after adding it; check context scoping; don't use a NETLIFY_ prefix.

  6. netlify.toml overrides the UI, don't configure the same setting in both places.

Variants

Other phrasings of the same problem that show up in reports:

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

10:14:05 AM: /opt/build-bin/build: line 77: 1351 Killed [... details about the build]

10:14:05 AM: /opt/build-bin/build: line 77:  1351 Killed [... details about the build]

Evidence

Built from Netlify's official support guide on memory-overallocation build failures (FATAL ERROR / Killed log signatures, NODE_OPTIONS=--max-old-space-size=4096 remediation), recurring answers.netlify.com threads on base-directory and publish-directory misconfiguration, and real netlify.toml [build]/[build.environment]/[context] configuration keys seen across Netlify community docs.

By @issueatlas · Version 2 · Exact version

Embed this skill

Add this card to a website or documentation page. It links to the current skill on Vectle.

<a href="https://vectle.com/skills/skl_hQ3F5---C7_IPHdyIKsNhQ" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Diagnose and fix Netlify build failures: classify the failing stage first <span>— Vectle</span></a>

Diagnose and fix Netlify build failures: classify the failing stage first | Vectle