Skip to content
shellhacks.dev
CI/CD

Fail a CI step on any error

Make a CI shell step fail on an error, an unset variable or a failed pipe stage with set -euo pipefail. GitHub Actions only adds pipefail with shell: bash.

1 min read
Summarize in AI

A CI step passes while a command inside it failed, because the failure was in the middle of a pipe.

Shell
bash -c 'false | cat; echo "default: kept going, status $?"'
bash -c 'set -e; false | cat; echo "-e alone: kept going, status $?"'
bash -c 'set -euo pipefail; false | cat; echo "never printed"'; echo "pipefail: step failed with $?"
bash -c 'set -u; echo "value: $UNDEFINED_VAR"'; echo "set -u: status $?"
Text
default: kept going, status 0
-e alone: kept going, status 0
pipefail: step failed with 1
bash: line 1: UNDEFINED_VAR: unbound variable
set -u: status 127

By default the status of a pipeline is that of its last command, so false | cat succeeds. set -o pipefail makes it the status of the last command that failed, -e exits on a non-zero status and -u treats an unset variable as an error. All three are in the set builtin documentation. The third line stops at the pipe, and the last line shows the unset variable error.

A run: step in GitHub Actions without a shell: key uses bash -e, with no pipefail, while shell: bash uses bash --noprofile --norc -eo pipefail, according to the workflow syntax reference. The flags also have exceptions inside if tests and && lists. They catch errors, but do not replace checking a command that is allowed to fail.

Share

More snippets

CI/CD

Check what changed in a pull request

List the files a pull request changed with git diff --name-only origin/main...HEAD. Three dots compare against the merge base, and a shallow checkout cannot do it.

2 min read
CI/CD

Print a warning annotation

Print ::warning file=...,line=...::message from a step to show an annotation on the run and in the pull request diff. Newlines in the text must be encoded.

1 min read
CI/CD

Run a script from the repo

Run a repository script from a workflow with run: ./script.sh only if Git stores it as executable. Otherwise the step fails with Permission denied, status 126.

2 min read

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.