Skip to content

entrypoint.sh: closing EOF delimiter never written to $GITHUB_OUTPUT when capture_stdout=true and remote command fails #416

Description

@lucaspsrrio

Summary

When capture_stdout: true and the remote command exits non-zero, entrypoint.sh dies (via set -e +
pipefail) before writing the closing EOF delimiter to $GITHUB_OUTPUT. The GitHub Actions
runner then fails the step with a confusing secondary error that masks the real remote command failure:

Error: Unable to process file command 'output' successfully.
Invalid value. Matching delimiter not found 'EOF'

Root cause

entrypoint.sh (pinned 0ff4204d59e8e51228ff73bce53f80d53301dee2, v1.2.5):

set -euo pipefail
...
if [[ "${INPUT_CAPTURE_STDOUT}" == 'true' ]]; then
  echo 'stdout<<EOF' >> "${GITHUB_OUTPUT}"
  "${TARGET}" "$@" | tee -a "${GITHUB_OUTPUT}"
  echo 'EOF' >> "${GITHUB_OUTPUT}"
else
  "${TARGET}" "$@"
fi

With pipefail, if ${TARGET} (drone-ssh, running the user's remote command) exits non-zero, the
whole TARGET | tee pipeline returns non-zero. With set -e also active, the script exits right there
— the next line (echo 'EOF' >> "${GITHUB_OUTPUT}") never runs. The output file ends up with the
opening stdout<<EOF delimiter and partial content, but no closing delimiter, which is exactly what the
runner rejects.

This only shows up on the failure path (remote command exits non-zero) — success runs never hit it,
which is presumably why it's gone unnoticed.

Isolated repro (no SSH needed)

run_entrypoint_snippet() {
  set -euo pipefail
  echo 'stdout<<EOF' >> "${GITHUB_OUTPUT}"
  "$@" | tee -a "${GITHUB_OUTPUT}"
  echo 'EOF' >> "${GITHUB_OUTPUT}"
}
fail_like_remote_command() { echo "some real error"; exit 1; }

GITHUB_OUTPUT=/tmp/mock_output.txt
: > "$GITHUB_OUTPUT"
run_entrypoint_snippet fail_like_remote_command
cat "$GITHUB_OUTPUT"

Output: stdout<<EOF + the echoed content, but no closing EOF line — the script exits with code 1
before reaching it. This mirrors a real production run of ours:
https://github.com/Infoglobo/suporte-producao-publegal-front/actions/runs/30305504299 (job
"Deploy (stg)"), which hit exactly this "Matching delimiter not found 'EOF'" error when the remote
deploy script legitimately failed a healthcheck.

Impact

  • The real error from the remote command gets buried under a second, unrelated runner-level error.
  • Any downstream step that depends on steps.<id>.outputs.stdout being valid on the failure path
    breaks silently (in our case, a diagnostics-extraction step that never runs with useful data).

Suggested fix

Write the closing delimiter unconditionally, regardless of ${TARGET}'s exit code — e.g. capture the
pipe's exit status via ${PIPESTATUS[0]} instead of relying on set -e/pipefail to propagate it, and
explicitly exit with that status only after the closing echo 'EOF' >> "${GITHUB_OUTPUT}":

if [[ "${INPUT_CAPTURE_STDOUT}" == 'true' ]]; then
  echo 'stdout<<EOF' >> "${GITHUB_OUTPUT}"
  set +e
  "${TARGET}" "$@" | tee -a "${GITHUB_OUTPUT}"
  status="${PIPESTATUS[0]}"
  set -e
  echo 'EOF' >> "${GITHUB_OUTPUT}"
  exit "${status}"
else
  "${TARGET}" "$@"
fi

Happy to open a PR with this if useful — wanted to confirm the root cause and preferred fix shape first.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions