From 3f6a53b51a5c464ca5929e9473aae80740653952 Mon Sep 17 00:00:00 2001 From: Jahvon Dockery Date: Thu, 27 Aug 2026 00:52:30 -0400 Subject: [PATCH] fix: surface failure output instead of discarding it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three changes, all aimed at the same problem: when a flow executable failed, the reason was hard or impossible to find from the run page. stderr was captured to a temp file, mined for a JSON error code, and deleted without ever being printed. Anything flow wrote there was lost outright โ€” most importantly the structured error envelope under --output json, whose message never reached the log. It is now echoed through. The failure annotation reported only an exit code. It now carries the error code and message when flow emits a structured envelope, with newlines folded to spaces so the workflow command cannot be terminated early. A step summary is written for both outcomes. flow collapses a multi-task run's output into a GitHub log group, so without this a reader had to expand the log just to learn whether the step passed; annotations and the summary render on the run page, where a collapsed group does not. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01R328pa3FUUfga4gYah1iQi --- scripts/execute.sh | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/scripts/execute.sh b/scripts/execute.sh index 1cbb2c2..366bf6c 100755 --- a/scripts/execute.sh +++ b/scripts/execute.sh @@ -45,10 +45,17 @@ else exit_code=$? fi -# Extract structured error code from stderr if the command failed +# Surface stderr. It was previously captured only to mine an error code and then +# discarded, so anything flow wrote there - notably the structured error envelope +# under --output json - never reached the log at all. error_code="" -if [ $exit_code -ne 0 ] && [ -s "$stderr_file" ]; then - error_code=$(jq -r '.error.code // empty' < "$stderr_file" 2>/dev/null || echo "") +error_message="" +if [ -s "$stderr_file" ]; then + if [ $exit_code -ne 0 ]; then + error_code=$(jq -r '.error.code // empty' < "$stderr_file" 2>/dev/null || echo "") + error_message=$(jq -r '.error.message // empty' < "$stderr_file" 2>/dev/null || echo "") + fi + cat "$stderr_file" >&2 fi set -e @@ -73,11 +80,36 @@ fi rm -f "$stderr_file" "$output_file" +# Write a step summary so the outcome is visible on the run page itself. flow +# collapses a multi-task run's output into a log group, so without this a reader +# has to expand the log just to learn whether the step passed. +if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then + if [ $exit_code -eq 0 ]; then + printf '### โœ… `flow %s`\n\n' "$EXECUTABLE_INPUT" >> "$GITHUB_STEP_SUMMARY" + else + { + printf '### โŒ `flow %s`\n\n' "$EXECUTABLE_INPUT" + printf 'Exit code `%s`' "$exit_code" + [ -n "$error_code" ] && printf ' ยท `%s`' "$error_code" + printf '\n' + if [ -n "$error_message" ]; then + printf '\n```\n%s\n```\n' "$error_message" + fi + } >> "$GITHUB_STEP_SUMMARY" + fi +fi + if [ "${CONTINUE_ON_ERROR:-false}" = "true" ]; then echo "Executable completed with exit code: $exit_code (continue-on-error enabled)" else if [ $exit_code -ne 0 ]; then - echo "::error::Executable failed with exit code $exit_code${error_code:+ ($error_code)}" + # Annotations render on the run page and in the PR, where a collapsed log + # group does not. Carry the message, not just the exit code. + annotation="flow $EXECUTABLE_INPUT failed with exit code $exit_code${error_code:+ ($error_code)}" + [ -n "$error_message" ] && annotation="$annotation: $error_message" + # A literal newline would end the workflow command early. + annotation=${annotation//$'\n'/ } + echo "::error::$annotation" exit $exit_code fi echo "Executable completed successfully"