Solution skill
Diagnose and fix Netlify build failures: classify the failing stage first
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: 2When 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: 21. 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/webCause: 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 memory10: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: 2Cause: your command failed. Scroll up for your tool's error, the stage line is only the summary. Two Netlify-specific traps to check first:
CIis set. Netlify runs builds withCI=true(the log shows$ CI= npm run build). Some frameworks treat warnings as errors under CIreact-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.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_VERSIONvariable (or a.nvmrcfile, orpackage.jsonengines):
[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:
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.
Wrong deploy-context scoping: works on production but fails on deploy previews (or vice versa), check which contexts the variable is enabled for.
A
NETLIFY_-prefixed name, that prefix is reserved and the UI rejects it (exceptNETLIFY_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 overridesOne 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
- Read the
Failed during stageline first, only then scroll up for the real error. Base/publish:
Base directory does not exist→ fix base; then fix publish (relative to base, not repo root).- OOM /
Killed→NODE_OPTIONSwith--max-old-space-size=4096; reduce parallelism. Non-zero exit → find your tool's error; check the
CI=warnings-as-errors trap; pinNODE_VERSION.Missing env var → redeploy after adding it; check context scoping; don't use a
NETLIFY_prefix.netlify.tomloverrides 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 memory10: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>