CodeBuild COMMAND_EXECUTION_ERROR: Decode the Exit Status
AWS CodeBuild's "COMMAND_EXECUTION_ERROR: Error while executing command" means one command in your buildspec returned a non-zero exit status, and CodeBuild stopped the build. It is the last line, not the cause. The cause is a few lines higher in the build log, in the output of whatever tool actually failed: a compiler, a test runner, a package manager, Git. The exit status narrows it: 127 means the shell could not find the command, 126 means it found it but could not run it, 128 is usually a Git fatal error, 137 means something killed the process, 1 and 2 mean "read what the tool printed". The surprise: most people fix the wrong thing because they read the red banner at the bottom and never scroll up. The fix is almost always in a line that was never red.
Jake runs a phone repair shop. His website is deployed by a pipeline that Ethan, his friend who does the technical side, set up so Jake could change prices and opening hours without calling anyone. It usually takes four minutes. This morning it turned red, the shop opens at nine, and the booking page still shows last week's prices.
Jake: "It says COMMAND_EXECUTION_ERROR, error while executing command. Which command? I didn't run any command, I changed a price."
Ethan: "Changing a price kicks off about a dozen commands behind the scenes. One of them refused to finish. Scroll up from the red line until you see the first thing that looks like a complaint from a program rather than a summary from AWS."
Jake: "Everything above it is green."
Ethan: "Green means 'I ran', not 'I was right'. Read up, not down. The final line tells you who reported the failure. The lines above it tell you what actually broke."
If "pipeline", "build" and "buildspec" are new words, you are in the right place, because Jake did not know them either and the whole page is written at his pace. The one page that helps before this one is our plain-English guide to AWS IAM, because the build runs as a role, and half the "permission denied" lines on this page come back to it.
What the error says, in shop terms
A build is the set of steps that turns the code in your repository into the thing that actually runs: installing dependencies, compiling, running tests, packaging. CodeBuild is the AWS service that runs those steps on a fresh machine every time. The steps are written in a file called the buildspec, a YAML file that lists commands in phases: install, pre_build, build, post_build. CodeBuild runs each command in a shell and looks at the number the command returns when it ends. Zero means it finished happily. Anything else means it did not, and CodeBuild stops and writes COMMAND_EXECUTION_ERROR on the phase.
Jake: "So the error means a command returned a number that wasn't zero."
Ethan: "That is all it means. It is like a technician handing back a phone with a tag that says 'not fixed'. The tag does not say why. The why is in the technician's notes, which are the log lines above."
Jake: "Why doesn't AWS just tell me the why?"
Ethan: "Because it did not write the why. The compiler did, or the test runner did, or Git did. CodeBuild only knows that the thing it ran came back unhappy. There are three layers: CodeBuild says a command failed, the shell gives you a number, and the program itself prints the actual reason. We work from the bottom up."
Not every red build is a command failure. The phase metadata can also show YAML_FILE_ERROR (the buildspec could not be read), a DOWNLOAD_SOURCE failure (the repository could not be fetched), a provisioning problem (the build machine never started) or an artifact upload failure. Those happen before or after your commands and have their own sections below. The phrase in this page's title belongs specifically to a command that ran and failed.
Find the failing command: Phase details, then Build logs
In the console: CodeBuild → Build projects → your project → Build history, then click the failed build. Two tabs matter. Phase details tells you which phase failed and shows a context line that usually includes the command and its exit status. Build logs is the full output of every command, and it is where the answer lives. If the project logs to CloudWatch, there is a link straight into the log stream too.
Here is the shape of what Jake found, with the real file name from his repository:
[Container] Running command npm run build
> storefront@1.0.0 build
> tsc && vite build
src/cart.ts:41:18 - error TS2339: Property 'totalPrice' does not exist on type 'Cart'.
[Container] Command did not exit successfully npm run build exit status 2
[Container] Phase complete: BUILD State: FAILED
[Container] Phase context status code: COMMAND_EXECUTION_ERROR
The reading order, every time:
- Phase details first. Note the phase (BUILD, INSTALL, DOWNLOAD_SOURCE) and the context line with the command and exit status.
- Open Build logs and jump to the
Running commandline for that command. - Read downward from there, stopping at the first line a program wrote about itself: an error, a fatal, a "not found", a file and line number.
- Only then look at the exit status, and use it to confirm what you just read, not to replace it.
- Write down the build ID, the phase, the command and that one line. That is the whole bug report.
Read it bottom to top. The context line is the summary. The "exit status 2" line is the number. The src/cart.ts:41:18 line is the answer: a TypeScript file, line 41, a property that does not exist. Exit status 2 on its own could have come from Bash, from TypeScript, or from almost anything; the program's own line is what tells you to open cart.ts.
Search the log for error, fatal, not found, denied, and for the exact text printed after Running command. Search is navigation, not judgment: some tools print perfectly ordinary lines containing the word "error", and a log with a dozen yellow warnings may have none of them involved.
Jake: "There are twelve warnings in yellow above it. One of those?"
Ethan: "A warning is not your culprit just because it is colorful. Find the first line that explains why this particular command returned non-zero. Yours is the TypeScript one. Someone renamed a field in the cart last week and the price page still uses the old name."
Jake: "That someone was me. I thought I was just changing a label."
The exit-status decoder: what each number is trying to tell you
The number after "exit status" is a convention, not an AWS code. Programs choose their own, and the same number can mean different things from different tools. But the common ones point in a direction, and that direction is usually right:
| Exit status | Usually means | Look above the line for | First move |
|---|---|---|---|
| 1 | General failure; the tool is unhappy | A test assertion, a compiler error, a permission denial, a script that quit | Fix the tool's first real error, rerun that exact command |
| 2 | Bad arguments or shell syntax; some tools use it for their own errors (TypeScript does) | Usage text, "invalid option", a parse message | Check the arguments; print the tool version |
| 126 | The shell found the file but could not run it | "Permission denied", "cannot execute binary file" | Executable bit, shebang line, right OS and chip |
| 127 | The shell could not find the command | "command not found" | Install it, or pick an image that has it |
| 128 | Git's number for any fatal error | "fatal: …" (shallow history, bad revision, authentication, not a repository) | Read the fatal line; check clone depth |
| 137 | 128 + 9: the process was killed | "Killed", memory pressure, a manual stop | Memory and timing, not the code |
| 255 | Program-specific fatal; SSH uses it | "Permission denied (publickey)", connection errors | Credentials and network for that program |
Two of these deserve a warning. 137 is often an out-of-memory kill, and it is also what you get when someone stops the build by hand or a wrapper kills a child process; the number does not prove memory. 128 is Git's catch-all, and "exit 128 means shallow clone" is a rule of thumb that is wrong as often as it is right. In both cases the fatal: or Killed line above is the evidence; the number is the hint.
Jake: "126 and 127 look the same to me. Found it, didn't run it. Didn't find it."
Ethan: "They are the difference between a technician who cannot find the screwdriver and one who finds it and discovers it is a Phillips when the screw is Torx. One needs a trip to the shop. The other needs the right tool from the drawer. 127 means install something. 126 means the thing you have is the wrong shape, or nobody gave it permission to run."
command -v node || true
command -v npm || true
command -v git || true
printf "PATH=%s\n" "$PATH"
ls -l ./scripts/build.sh
file ./scripts/build.sh
Drop those lines into the failing phase, temporarily, and the log tells you which case you have. If your own script lacks the executable bit, fix it in the repository with chmod +x scripts/build.sh and commit, or call it as bash scripts/build.sh, which needs no executable bit but does need the file to be valid Bash.
The same answers from the terminal
If the console is slow or you want the structured version, three commands cover it. The first lists recent builds so you have an ID; the second pulls the phases, statuses and context messages for one build; the third shows the project's source, buildspec setting and image, which is what you compare against your laptop when "it works here":
aws codebuild list-builds-for-project --project-name my-project --sort-order DESCENDING --region us-east-1 --query "ids[0:10]"
aws codebuild batch-get-builds --ids "my-project:BUILD-UUID" --region us-east-1 \
--query "builds[0].{status:buildStatus,phases:phases[*].{phase:phaseType,status:phaseStatus,contexts:contexts}}" --output json
aws codebuild batch-get-projects --names my-project --region us-east-1 \
--query "projects[0].{source:source,environment:environment,serviceRole:serviceRole}"
If the console and the CLI disagree about anything, check which account and Region each is looking at before you decide AWS is inconsistent. aws sts get-caller-identity tells you the account; the console's Region selector and your CLI profile's Region are set independently, and a "fixed" build in the wrong Region has fooled better people than Jake.
Which phase failed, and why that decides where the fix goes
The buildspec has four command phases, but a build has more phases than that. Knowing which one failed tells you whether the problem is your commands at all:
| Phase | What happens | Typical failure |
|---|---|---|
| PROVISIONING | The build machine and image are prepared | Image pull or environment problem; nothing of yours ran yet |
| DOWNLOAD_SOURCE | Your repository is fetched and the buildspec located | Repository access, missing buildspec, YAML parse error |
| INSTALL | Runtimes chosen, dependencies installed | Unsupported runtime, package install failure |
| PRE_BUILD | Checks, logins, credentials | Authentication, environment validation |
| BUILD | Compile, test, package | Compiler errors, failing tests, missing commands |
| POST_BUILD | Follow-up steps, publishing prep | Upload commands, notification scripts, Docker push |
| UPLOAD_ARTIFACTS | Configured artifacts are collected and uploaded | Missing files, wrong paths, destination permissions |
A failure in BUILD belongs in your code or your tests. A failure in INSTALL belongs in your dependencies or your image. A failure in DOWNLOAD_SOURCE is not a command failure at all, and editing the buildspec will not touch it. One detail that bites in BUILD: in buildspec version 0.2, commands within a phase share one shell, so a cd on one line changes where the next line runs. Version 0.1 ran each command in its own shell. Use 0.2 for anything new, and remember that the shared shell is why a path that worked on line three fails on line nine.
Jake: "So the phase is like which bench in the shop the phone was on when it broke."
Ethan: "Yes. If it broke on the intake desk, the technician never touched it, and blaming the technician wastes the morning. Yours broke on BUILD, which is the repair bench. That is your code."
A buildspec that tells you what went wrong
A buildspec is a recipe and, during an incident, a map. Give each phase one job, print version checks at the top so the log shows what tools you actually had, and keep commands short enough that the failing one is obvious. This is the shape Ethan uses for Jake's storefront:
version: 0.2
phases:
install:
runtime-versions:
nodejs: 22
commands:
- node --version
- npm --version
- npm ci
pre_build:
commands:
- echo "Starting verification"
- git rev-parse --short HEAD || true
build:
commands:
- npm test -- --runInBand
- npm run build
post_build:
commands:
- echo "Build command phase complete"
artifacts:
files:
- "dist/**/*"
The || true after the Git command is deliberate and narrow: that line is a diagnostic that may legitimately fail on a source without a .git folder, and the build should not die for it. Putting || true after npm run build would be something else entirely: it tells the shell to report success when the build failed, and you would ship a broken site with a green tick. If you need cleanup that runs even after a failure, use a finally block, which runs after the phase's commands whether they passed or not and does not change the outcome:
version: 0.2
phases:
build:
commands:
- echo "Compiling application"
- npm run build
finally:
- echo "Build phase finished; collecting diagnostics"
- ls -la
CodeBuild also offers on-failure settings (ABORT, CONTINUE and retry variants) on supported EC2 compute. They do not apply to Lambda compute or reserved capacity, and retries are for things that might genuinely be temporary, like a flaky download, never for a compile error that will fail identically every time.
Jake: "Can't I just click Retry? It's one button."
Ethan: "Retry helps when the thing that failed was temporary, like a download that timed out. Your file still has the wrong field name in it. It will not compile differently because you pressed the button twice."
Exit status 1 and 2: let the tool speak
Status 1 is the broadest number in the table, and status 2 is nearly as broad. Both mean "the program is unhappy", and the only way to know why is to find the program's own first complaint. For npm ci, that is a lockfile or dependency-resolution message. For Maven, it is the first compilation or test failure, not the "BUILD FAILURE" banner at the end. For a shell script you wrote, it is whatever command the script ran just before it gave up.
When the log does not show enough, add a little temporary noise: pwd, ls -la, the compiler version, a verbose flag on the test runner. A surprising number of "it cannot find the file" failures turn out to be "you are in the wrong folder". Take the diagnostics out again once you understand the failure, especially anything that could print environment values.
126 and 127: the right tool, the wrong tool, and no tool
127, command not found, is the most common one on a first build, and it is almost always about the image. CodeBuild's managed images come with a known set of tools; custom images have whatever you put in them; your laptop has whatever you installed over three years. If pnpm or docker or python3.13 is not in the image, no amount of fixing your code will conjure it.
126 is subtler: the file exists and the shell will not run it. Check the executable bit, the shebang (the #! line that names the interpreter), and whether a downloaded binary matches Linux and the build machine's architecture. A script edited on Windows can carry a carriage return at the end of its shebang, which makes Linux look for an interpreter whose name ends in an invisible character.
pwd
uname -m
printf "PATH=%s\n" "$PATH"
command -v python || true
command -v node || true
command -v docker || true
ls -l scripts/
head -n 1 scripts/build.sh
If the script exists but its shebang names an interpreter the image does not have, changing the file permission fixes nothing. #!/usr/bin/env bash is the safe form, and Bash has to be in the image.
Jake: "But pnpm is on my laptop. I use it every day."
Ethan: "Your laptop and the CodeBuild container are different kitchens. Check what ingredients the container has before you blame the recipe."
Exit 128: Git, and the history you did not download
When git describe, git fetch or any Git command exits 128, the fatal: line above it is the whole diagnosis. The usual suspects: incomplete history, a reference that does not exist, a missing .git folder, or a credentials problem. One of these is so common on CodeBuild that it has a setting of its own.
A shallow clone downloads only the most recent commits, which makes source download faster and is the default on many project configurations. It also means that a script which asks Git for the nearest tag, or walks back through history to compute a version number, may find nothing to walk. The project's source settings have a Git clone depth option (the API calls it gitCloneDepth); zero is the conventional way to ask for full history. If the source arrives as a CodePipeline artifact instead of a Git checkout, there may be no .git folder at all, and no depth setting will help; pass the version in as metadata instead.
git status --short
git rev-parse --is-shallow-repository
git rev-parse --verify HEAD
git describe --tags --always
git log -1 --oneline
aws codebuild batch-get-projects --names my-project --region us-east-1 \
--query "projects[0].source.{type:type,location:location,gitCloneDepth:gitCloneDepth}"
Jake: "Our version number comes from git describe --tags. That is the line that failed last month."
Ethan: "The script is asking Git about its family history. If you only downloaded the newest page of that history, the old tag is not there. Deeper clone, or stop asking Git for the version and write it down somewhere the build can read."
The build image: why "it works on my laptop" is not evidence
The environment image is the operating system and tool set your build runs inside. It decides which commands exist, which runtimes can be selected, and which versions you get. It is not cosmetic. If the same command returns 127 in CodeBuild and works at home, the image is the first suspect and usually the last.
In the console: open the project, Edit, look at Environment and the chosen managed or custom image. From the CLI, list the current curated images rather than trusting an image name from a two-year-old tutorial:
aws codebuild list-curated-environment-images --region us-east-1
On managed images that support it, pick runtimes explicitly under phases.install.runtime-versions. That pins what you get when the image's default moves. The runtime tables grew during 2026: Node.js 24, Python 3.14, Go 1.25, Corretto 25 and .NET 10 are in the newer images, and in July 2026 CodeBuild added a separate host kernel choice for on-demand build hosts, Amazon Linux 2023 with a Linux 6 kernel alongside the older Amazon Linux 2 host. The host kernel is the machine underneath; the image is the container on top. Changing one does not change the other.
version: 0.2
phases:
install:
runtime-versions:
python: 3.13
commands:
- python --version
- python -m pip install -r requirements.txt
build:
commands:
- python -m pytest
Custom images are the right answer when you need a precise compiler or a native dependency set, and they make you the person who patches them. For most teams a current managed image plus pinned runtime versions is the simpler and safer default.
YAML_FILE_ERROR: the build that never ran a command
If the phase says YAML_FILE_ERROR, CodeBuild could not read your buildspec, and nothing you do to the application will help. The usual causes are indentation (YAML is strict and tabs are not spaces), a key it does not recognize, a buildspec that is not where the project expects it, or a runtime that the chosen image does not offer. Two traps catch nearly everyone once.
The first is a colon followed by a space inside a command. YAML reads echo Build: starting as a key called "echo Build" with a value "starting". Quote the command, or use a block scalar:
version: 0.2
phases:
build:
commands:
- "echo Build: starting"
- npm run build
# or, for anything longer:
version: 0.2
phases:
build:
commands:
- |
echo "Build: starting"
npm run build
The second is the message This build image requires selecting at least one runtime version. It means the image wants a runtime-versions entry under install and you did not give it one, or gave it one the image does not support. Add a runtime the image actually offers; inventing a version string just produces the next error. And check where the project expects the buildspec: the default is buildspec.yml at the source root, but a project can point at a custom path, use an inline buildspec, or receive an override when the build starts.
Jake: "Should I just put every command under build so the YAML stops complaining about phases?"
Ethan: "The structure is not the enemy. Fix the indentation and pick an image that has your runtime. Then the log will finally show the command you are trying to run, and we can argue about that one instead."
Exit 137: killed, but by whom
137 means the process received a kill signal. Memory exhaustion is the common cause, and it is not the only one: a manual stop, a parent script killing its child, or an external timeout produce the same number. Look for a "Killed" message, check whether the build dies at the same point every time (the bundler on the big source maps, the test runner spawning twenty workers), and compare the time of death with anything else that happened.
If memory really is short, a larger compute type is the fix, and CodeBuild offers several with different capacity per Region; look at what your project is actually on rather than copying a number from an old guide. If the process was stopped on purpose, more memory changes nothing. Our ECS exit code 137 page is the same number one layer down, inside a running container, if your build then fails there too.
Exit 255: SSH, credentials and the service role
255 after an SSH command, a Git-over-SSH fetch or a custom binary means "that program hit something fatal", and for SSH it is almost always connection or authentication: Permission denied (publickey), a DNS failure, a host-key problem. Read the program's line.
Do not confuse that with an AWS permission error. The build runs as a service role, an IAM role CodeBuild assumes, and that role needs exactly the actions your build performs: read the artifact bucket, push to the container registry, fetch a secret. An AccessDenied from an AWS CLI command inside the build names the action and the resource; fix those two, narrowly. Granting the role administrator rights to turn a red build green is how shops end up on the breach list. Our AccessDenied decoder walks the message apart.
Intermittent download failures are network: DNS, VPC routing, proxy, the package host. Consistent "authorization denied" is credentials. The first wants a retry policy; the second wants a fix, and retrying it twenty times is twenty failures.
Run the buildspec on your own machine
When remote logs are not enough, the CodeBuild local agent runs your buildspec in the same kind of container on your own computer. You need Git and Docker locally, and a build image to run in:
docker pull public.ecr.aws/codebuild/local-builds:latest
docker pull public.ecr.aws/codebuild/amazonlinux-x86_64-standard:4.0
curl -O https://raw.githubusercontent.com/aws/aws-codebuild-docker-images/master/local_builds/codebuild_build.sh
chmod +x codebuild_build.sh
./codebuild_build.sh -i public.ecr.aws/codebuild/amazonlinux-x86_64-standard:4.0 -a ./codebuild-local-artifacts
Pick a current image rather than the one in the example if you are comparing against production; on an ARM machine use the local-builds:aarch64 agent and an ARM image. If the local build fails on the same command with the same message, you have a reproduction you can fix at your desk. If it passes locally and fails hosted, compare the things that differ: environment variables, IAM credentials, network access, how the source was checked out, cached dependencies, image version, CPU architecture, secrets, file paths. One of those is your bug.
Be careful with commands that publish, push images or change cloud resources: a local run may pick up your own credentials. Comment the side-effecting steps out while you diagnose.
Fails only inside CodePipeline?
A project that passes when you start it by hand and fails as a CodePipeline action is usually receiving different source. A pipeline can hand CodeBuild an input artifact, a zip of files, rather than a Git checkout. Anything that depends on .git, on history or on tags behaves differently or not at all. Compare the pipeline's input artifact with a direct checkout, and confirm the revision and the buildspec that revision expects.
Environment variables have an order of precedence too: overrides set when the build starts beat the project's variables, which beat the ones in the buildspec. Keep secrets out of plaintext buildspec variables, and keep environment dumps out of logs other people can read. And when the pipeline only says "CodeBuild build failed", open the individual build record: the pipeline tells you which action failed, the build log tells you which command.
Monorepos and the wrong working directory
"No such file" with the file plainly in the repository usually means the command ran from a different folder than you imagined. Monorepos with several applications, infrastructure folders and more than one buildspec do this constantly. The primary source folder is in the CODEBUILD_SRC_DIR variable; print it, print pwd, and list what is actually there:
printf "Working directory: %s\n" "$PWD"
printenv CODEBUILD_SRC_DIR
ls -la
find . -maxdepth 3 -name package.json -print
If Jake's storefront lives in services/storefront, make that explicit in every phase rather than hoping a cd survives the phase boundary, and point the artifact base directory at the real output folder:
version: 0.2
phases:
install:
commands:
- cd services/storefront
- npm ci
build:
commands:
- cd services/storefront
- npm run build
artifacts:
base-directory: services/storefront/dist
files:
- "**/*"
Permission-denied lines in this area usually mean the build runs as a different user than your laptop does. Check file ownership and the executable bit, and keep file-mode changes in source control. Resist the urge to answer every permission error with a sudo; install to a writable folder or fix the image instead.
When the dependency step fails, not your code
npm ci, pip install and mvn package can all return 1 with your source code entirely correct, because dependency resolution happens before compilation. The classic: a teammate changed package.json and did not commit the updated lockfile. Their machine still has the old node_modules and works; CI starts clean and fails.
| Command that failed | The real message to find | Likely repair |
|---|---|---|
npm ci | Lockfile or dependency-resolution error | Regenerate and commit the intended lockfile |
python -m pip install | "No matching distribution", missing compiler | Match runtime and platform; pin a version with wheels |
mvn package | "Could not resolve dependency", compiler output | Repository credentials, then the compiler line |
docker build | No Docker daemon, or a RUN step failed | Docker setup first, then the Dockerfile stage |
aws ecr get-login-password | AccessDenied or Region mismatch | Service role permissions, same Region as the repository |
If the build runs inside a VPC without a way out to the internet, package downloads time out while the source is right there. That is routing and DNS, not a version problem; pinning a different package at random will not fix it.
Jake: "Could I just delete the lockfile? That seems easy."
Ethan: "Your lockfile is the shopping list for the exact versions the build expects. Repair a stale list. Throwing it away changes what gets installed, and then Tuesday's build and Thursday's build are different products."
Docker builds: two failures wearing one error
A docker build or docker push inside CodeBuild can fail in two different places: Docker itself cannot run in the build environment, or the build inside the Dockerfile failed. docker version and docker info tell you whether the CLI can reach a daemon at all; that depends on the project's privileged-mode or remote-Docker setup. A failure inside a RUN instruction shows the Dockerfile stage and the shell's exit status, surfaced through Docker and then through CodeBuild, so the summary is two layers away from the cause. An ECR push that fails wants the repository to exist, the image name and tag to match, the account and Region to be right, and the service role to have the ECR actions; a login that worked in one Region does not authenticate you to a repository in another. Our ImagePullBackOff page picks up where the push succeeds and the pull does not.
Debugging without printing your passwords
The tempting diagnostic is env or set -x, and it will print every variable including the ones you would rather not see in a log that three colleagues and a ticketing system can read. Print safe facts instead: versions, the working directory, which executables exist, and whether a secret is present without showing it:
if [ -n "${DEPLOY_TOKEN:-}" ]; then
echo "DEPLOY_TOKEN is configured"
else
echo "DEPLOY_TOKEN is missing"
fi
If a token or key has already appeared in a build log, treat it as a credential incident and rotate it. Deleting the line does not delete the copies the log system already kept. Secrets belong in a secrets store the build reads at runtime, which is what our Secrets Manager page is about.
The decision path when the first fix does not work
If your change did not clear the error, do one thing at a time, cheapest evidence first:
- Capture the complete failing command and its first meaningful error line.
- Read the failed phase and its context through Phase details or
batch-get-builds. - Decode the exit status, then let the program's own message overrule the number.
- Compare image, runtime, shell, working directory and installed tools with the place where it works.
- For Git commands, check
.git, the revision, the clone depth and credentials. - For YAML errors, validate the syntax and the buildspec path before rerunning anything.
- Run the same buildspec locally in a matching image.
- Change one variable, rerun, compare the logs. Never guess from the top-level banner.
A build that gets further after your change and then fails on a different command is progress. The second failure is a second bug, and it gets the same method.
Worked example: from exit 127 to green
Jake's storefront runs a twelve-command buildspec. After the TypeScript fix, the build got to command eight and died with exit 127: pnpm: command not found. Not a code problem, not a CodeBuild outage: the shell could not find the package manager the buildspec assumed. The fix lives in install, where the tool is enabled and its version is printed so the next failure, if any, is obvious:
version: 0.2
phases:
install:
runtime-versions:
nodejs: 22
commands:
- node --version
- corepack --version
- corepack enable
- pnpm --version
- pnpm install --frozen-lockfile
build:
commands:
- pnpm run build
That assumes the image ships Corepack; check before trusting it, and pin the package-manager version in the project so a future build does not quietly change tools. The arithmetic of guessing: a build that takes three minutes to fail, retried blind four times, is twelve minutes of waiting and no information. One command -v pnpm line gave the answer in the first run.
What a red build costs, and the limits behind some of them
Failed builds use billable build minutes like successful ones, on the compute type the project selects. Six minutes to fail, started five times, is thirty minutes of compute to learn the same thing five times; the exact dollars depend on the Region and compute type, and the current CodeBuild pricing page is the only honest source for the per-minute rate. The cheaper habit is the one this page keeps repeating: read the log once, properly.
If the failure is in provisioning or capacity rather than a command, exit codes will not tell you about a quota. Check the project's service limits in the right Region before changing roles or compute types on a hunch.
Not meeting this at 8:45 a.m. again
Keep the buildspec in source control. Print version checks at the top of install. Pin runtime versions when consistency matters. Use the same lockfile discipline in CI and on laptops, and confirm the artifact path before the build ends, because a compile that succeeds followed by an empty dist is still a failed delivery. Run tests in the same image when the code depends on system packages. Keep secrets in a secrets store, and never echo tokens in diagnostics. And prefer a fast red build with a clear reason over a green one that skipped the tests: a green build that silently skipped verification is worse than a red one that told you exactly what failed.
Jake: "Customers are asking about the new prices. Can I push last week's package and sort this out tonight?"
Ethan: "Tell customers the prices are coming and fix it properly, yes. Publish a package that never compiled, no. A red build is frustrating. A false green build puts the frustration in your customer's hands at the counter."
The exact CodeBuild questions people search for
What does aws codebuild COMMAND_EXECUTION_ERROR mean?
A command in your buildspec returned a non-zero exit status and CodeBuild stopped the phase. It is a summary line, not the cause. Open the failed build's Phase details for the command and exit status, then read the Build logs above the summary for the program's own error.
How do I fix CodeBuild exit status 1?
Find the failing program's first real error line in the build log. Status 1 is generic: compiler errors, failing tests, dependency resolution and custom scripts all return it. Fix that specific message, then rerun the exact command.
What does exit status 2 mean in CodeBuild?
Usually bad command arguments or shell syntax, but some tools use 2 for their own failures; TypeScript's compiler is one. Read the usage or error text the program printed just above the exit line.
Why does CodeBuild return exit status 126?
The shell found the file but could not execute it. Check the executable bit, the shebang line, Windows line endings, and whether a downloaded binary matches Linux and the build machine's architecture.
How do I fix CodeBuild exit status 127?
127 is "command not found". The build image does not contain the tool, or it is not on PATH. Pick a managed image that has it, install it in the install phase, or fix the path.
Why does git exit 128 in AWS CodeBuild?
Git uses 128 for any fatal error: shallow history without the tag you asked for, a bad revision, authentication, or no .git directory at all. Read the fatal: line, then check the project's Git clone depth setting; zero requests full history.
Is CodeBuild exit status 137 always out of memory?
No. 137 means the process was killed. Memory exhaustion is the common cause, but a manual stop or a parent process killing a child gives the same number. Look for a Killed message and check whether it dies at the same step every time.
What does CodeBuild exit status 255 mean?
It is program-specific. SSH returns 255 for connection and authentication failures such as Permission denied (publickey). Diagnose that program's output, not the number.
Where do I find the CodeBuild build failed reason?
Open the failed build in the CodeBuild console: Phase details shows the failed phase and context, Build logs shows the command output. From the CLI, aws codebuild batch-get-builds returns the phases and their context messages.
How do I fix codebuild YAML_FILE_ERROR?
Fix the buildspec itself: indentation with spaces not tabs, quote any command containing a colon and a space, make sure the file is where the project expects it, and give runtime-versions a runtime the selected image supports.
What buildspec phases does CodeBuild execute?
The buildspec command phases are install, pre_build, build and post_build. The build itself also passes through SUBMITTED, PROVISIONING, DOWNLOAD_SOURCE, UPLOAD_ARTIFACTS and FINALIZING, which can fail before or after your commands run.
Why does CodeBuild work locally but fail in AWS?
The build image, runtime versions, environment variables, credentials, Git clone depth and network access differ from your machine. Print versions and PATH in the install phase, and run the buildspec locally with the CodeBuild agent to compare.
How do I set runtime-versions in buildspec.yml?
Under phases.install, add runtime-versions with a runtime and version the managed image supports, for example nodejs: 22 or python: 3.13. Custom images do not use this mechanism.
How can I run a CodeBuild buildspec locally?
Install Docker and Git, pull public.ecr.aws/codebuild/local-builds and a build image, download codebuild_build.sh from the aws-codebuild-docker-images repository, and run it with -i for the image and -a for an artifact folder.
Why does CodeBuild fail in DOWNLOAD_SOURCE?
The repository or input artifact could not be fetched, or the buildspec was not found where the project expects it. This happens before any command runs, so editing commands will not fix it; check source access and the buildspec path.
Can on-failure CONTINUE fix a CodeBuild command error?
No. It changes how the phase proceeds after a failure on supported EC2 compute, and it is not available on Lambda compute or reserved capacity. The underlying command still failed and still needs fixing.
Jake's morning had two bugs, which is usual. The first was a field he had renamed in cart.ts without noticing it was used elsewhere; the compiler had said so on line 41, in white text, four lines above the red banner. The second was a package manager the build image did not have, which showed up only once the first bug was gone. Both fixes took minutes once he read upward. The shop opened at nine with the right prices, and the buildspec now prints its tool versions at the top so that the next time something is missing, the log says so before anything else runs.
📌 If you keep one line from this page
COMMAND_EXECUTION_ERROR is the summary; the exit status is the hint; the program's own line above them is the answer.
127 install it, 126 fix its permissions or shape, 128 read Git's fatal line, 137 ask who killed it, 1 and 2 read what the tool said.
Revision note. Written October 9, 2026, with the Amazon Linux 2023 host kernel and the Node.js 24 images in the matrix. Measure twice, cut once: read the line above the error before you change the build.