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.
Summary
When
capture_stdout: trueand the remote command exits non-zero,entrypoint.shdies (viaset -e+pipefail) before writing the closingEOFdelimiter to$GITHUB_OUTPUT. The GitHub Actionsrunner then fails the step with a confusing secondary error that masks the real remote command failure:
Root cause
entrypoint.sh(pinned0ff4204d59e8e51228ff73bce53f80d53301dee2, v1.2.5):With
pipefail, if${TARGET}(drone-ssh, running the user's remote command) exits non-zero, thewhole
TARGET | teepipeline returns non-zero. Withset -ealso active, the script exits right there— the next line (
echo 'EOF' >> "${GITHUB_OUTPUT}") never runs. The output file ends up with theopening
stdout<<EOFdelimiter and partial content, but no closing delimiter, which is exactly what therunner 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)
Output:
stdout<<EOF+ the echoed content, but no closingEOFline — the script exits with code 1before 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
steps.<id>.outputs.stdoutbeing valid on the failure pathbreaks 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 thepipe's exit status via
${PIPESTATUS[0]}instead of relying onset -e/pipefailto propagate it, andexplicitly
exitwith that status only after the closingecho 'EOF' >> "${GITHUB_OUTPUT}":Happy to open a PR with this if useful — wanted to confirm the root cause and preferred fix shape first.