Skip to content
Latchkey

Bitbucket "after-script" Not Running or Masking Failures

after-script runs after the main script whether it passed or failed - useful for cleanup and reporting. Its own exit code does not fail the step, which surprises teams who put real assertions there.

What this error means

Cleanup or reporting placed in after-script does not behave as expected: a failing command there does not fail the build, or commands are missing context because the step already failed. The main result is decided by script, not after-script.

bitbucket-pipelines.yml
script:
  - ./run-tests.sh
after-script:
  - ./upload-coverage.sh   # runs even if tests failed; its exit code is ignored

Diagnose it: schema, branch match, or step isolation?

Bitbucket validates the pipeline file on push, and a schema error disables the pipeline rather than failing a build, which looks like nothing happened. Each step also runs in a fresh container, so nothing carries between steps unless declared.

Terminal
curl -X POST -H "Content-Type: application/x-yaml" \
  --data-binary @bitbucket-pipelines.yml \
  https://api.bitbucket.org/2.0/repositories/<workspace>/<repo>/pipelines/validate

Common causes

Expecting after-script to affect the step result

after-script is for teardown. A non-zero exit there does not turn a passing step red, so assertions placed there never gate the build.

Assuming after-script is skipped on failure

It runs after the main script regardless of pass/fail. Cleanup written assuming success may hit a half-finished state from a failed script.

How to fix it

Use after-script only for cleanup and reporting

Keep teardown idempotent and tolerant of a failed main script. Use BITBUCKET_EXIT_CODE to branch on the result.

bitbucket-pipelines.yml
script:
  - ./run-tests.sh
after-script:
  - if [ "$BITBUCKET_EXIT_CODE" != "0" ]; then ./collect-logs.sh; fi
  - ./teardown.sh || true

Keep real assertions in the main script

  1. Move any check that must fail the build into script, not after-script.
  2. Treat after-script as best-effort cleanup that cannot fail the step.
  3. Use BITBUCKET_EXIT_CODE inside after-script to react to the result.

How to prevent it

  • Put pass/fail logic in script; put cleanup in after-script.
  • Make after-script tolerant of a failed main script.
  • Read BITBUCKET_EXIT_CODE to know whether the step passed.

Frequently asked questions

What causes Bitbucket "after-script" not running or masking failures?
There are 2 common causes: expecting after-script to affect the step result and assuming after-script is skipped on failure. after-script is for teardown.
How do I fix Bitbucket "after-script" not running or masking failures?
There are 2 fixes depending on which cause you have: use after-script only for cleanup and reporting and keep real assertions in the main script. Work through them in order, since the first is the most common.
What does Bitbucket "after-script" not running or masking failures actually mean?
Cleanup or reporting placed in after-script does not behave as expected: a failing command there does not fail the build, or commands are missing context because the step already failed.
How do I stop Bitbucket "after-script" not running or masking failures happening again?
Put pass/fail logic in script; put cleanup in after-script. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card