Skip to content

fix(docs-noob-tester): replace STATUS=$(curl) with until curl to survive set -e#28624

Merged
pelikhan merged 2 commits intomainfrom
copilot/fix-docs-noob-tester-exit-code-7
Apr 26, 2026
Merged

fix(docs-noob-tester): replace STATUS=$(curl) with until curl to survive set -e#28624
pelikhan merged 2 commits intomainfrom
copilot/fix-docs-noob-tester-exit-code-7

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 26, 2026

GitHub Actions runs bash steps with set -e. The command substitution STATUS=$(curl ...) propagates curl's exit code 7 (CURLE_COULDNT_CONNECT) directly to bash, which terminates the step on the very first connection attempt—the retry loop never retried.

Changes

  • docs-noob-tester.md — Wait for server readiness step: Replace STATUS=$(curl ...) with until curl -sf ... — bash exempts loop conditions from set -e, so a failed curl causes the loop body to run instead of killing the step.
  • Crash detection: added kill -0 $(cat /tmp/server.pid) inside the loop to distinguish server crash from slow startup.
  • Timeout diagnostics: explicit failure after 135s that dumps /tmp/preview.log to surface the actual startup error.
  • docs-noob-tester.lock.yml: recompiled.
# Before — exits immediately when curl returns code 7
STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:4321/gh-aw/)

# After — curl failure just re-enters the loop body
until curl -sf http://localhost:4321/gh-aw/ > /dev/null 2>&1; do
  if [ -f /tmp/server.pid ] && ! kill -0 "$(cat /tmp/server.pid)" 2>/dev/null; then
    echo "::error::Documentation server process died before becoming ready. Server log:"
    cat /tmp/preview.log
    exit 1
  fi
  WAITED=$((WAITED + 3))
  if [ $WAITED -ge $MAX_WAIT ]; then
    echo "::error::Documentation server did not start after ${MAX_WAIT}s. Server log:"
    cat /tmp/preview.log
    exit 1
  fi
  echo "Waiting for server... ($WAITED/${MAX_WAIT}s)"
  sleep 3
done

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v9
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linu--jq (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linu--jq (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json .cfg 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env -json GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)

If you need me to access, download, or install something from one of these locations, you can either:

The previous STATUS=$(curl ...) command substitution was exiting with
code 7 (CURLE_COULDNT_CONNECT) on the very first attempt because GitHub
Actions runs bash steps with 'set -e', causing the entire step to fail
immediately rather than retrying.

Replace with 'until curl -sf ...' which puts curl in a test/condition
position that is immune to 'set -e'. Also adds:
- Server process liveness check (detects crash vs timeout)
- Explicit timeout failure with log dump for easier debugging"

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/3942cff2-1b61-441a-b1a4-1f302e24e20f

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix exit code 7 for server readiness check in docs-noob-tester fix(docs-noob-tester): replace STATUS=$(curl) with until curl to survive set -e Apr 26, 2026
Copilot AI requested a review from gh-aw-bot April 26, 2026 19:41
@pelikhan pelikhan marked this pull request as ready for review April 26, 2026 20:51
Copilot AI review requested due to automatic review settings April 26, 2026 20:51
@pelikhan pelikhan merged commit 6dea27e into main Apr 26, 2026
19 checks passed
@pelikhan pelikhan deleted the copilot/fix-docs-noob-tester-exit-code-7 branch April 26, 2026 20:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the docs-noob-tester workflow’s “wait for server readiness” logic to reliably retry under set -e, while improving failure diagnostics when the docs server crashes or never becomes ready.

Changes:

  • Replaced STATUS=$(curl ...) polling with an until curl -sf ...; do ...; done loop so connection failures don’t terminate the step under set -e.
  • Added server crash detection via PID liveness checks and improved timeout diagnostics by dumping /tmp/preview.log.
  • Regenerated the compiled workflow lock file.
Show a summary per file
File Description
.github/workflows/docs-noob-tester.md Updates the readiness wait loop and adds crash/timeout diagnostics for the docs server.
.github/workflows/docs-noob-tester.lock.yml Regenerates the compiled workflow to include the updated readiness logic.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 2/2 changed files
  • Comments generated: 3

echo "Waiting for server... ($i/45) (status: $STATUS)" && sleep 3
MAX_WAIT=135 # 45 attempts × 3s = 135s max wait
WAITED=0
until curl -sf http://localhost:4321/gh-aw/ > /dev/null 2>&1; do
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curl -sf in the until condition has no connect/overall timeout, so a stalled connect/read can block the loop longer than the intended 3s cadence and make the effective wait exceed (or behave inconsistently with) MAX_WAIT. Consider adding --connect-timeout/--max-time (or similar) so each probe is bounded and the MAX_WAIT semantics stay reliable.

Suggested change
until curl -sf http://localhost:4321/gh-aw/ > /dev/null 2>&1; do
until curl -sf --connect-timeout 1 --max-time 2 http://localhost:4321/gh-aw/ > /dev/null 2>&1; do

Copilot uses AI. Check for mistakes.
Comment on lines +57 to +60
if [ -f /tmp/server.pid ] && ! kill -0 "$(cat /tmp/server.pid)" 2>/dev/null; then
echo "::error::Documentation server process died before becoming ready. Server log:"
cat /tmp/preview.log
exit 1
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The crash-detection check uses kill -0 "$(cat /tmp/server.pid)" which is vulnerable to races/invalid contents (e.g., empty/partial PID file) and reintroduces a command substitution in a set -e script. Safer is to read the PID with shell redirection (read -r pid < /tmp/server.pid) and validate it’s a non-empty numeric PID before calling kill -0.

Suggested change
if [ -f /tmp/server.pid ] && ! kill -0 "$(cat /tmp/server.pid)" 2>/dev/null; then
echo "::error::Documentation server process died before becoming ready. Server log:"
cat /tmp/preview.log
exit 1
if [ -f /tmp/server.pid ]; then
read -r pid < /tmp/server.pid || pid=
case "$pid" in
''|*[!0-9]*)
echo "::error::Documentation server PID file is invalid before readiness check. Server log:"
cat /tmp/preview.log
exit 1
;;
esac
if ! kill -0 "$pid" 2>/dev/null; then
echo "::error::Documentation server process died before becoming ready. Server log:"
cat /tmp/preview.log
exit 1
fi

Copilot uses AI. Check for mistakes.
[ "$STATUS" = "200" ] && echo "Server ready at http://localhost:4321/gh-aw/!" && break
echo "Waiting for server... ($i/45) (status: $STATUS)" && sleep 3
MAX_WAIT=135 # 45 attempts × 3s = 135s max wait
WAITED=0
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow imports shared/docs-server-lifecycle.md, but that shared document’s “Waiting for Server Readiness” section still shows the old STATUS=$(curl ...) pattern (shared/docs-server-lifecycle.md:54-58). Consider updating the shared instructions (or noting the newer pattern here) to avoid the prompt/documentation drifting from the actual pre-agent step behavior.

Suggested change
WAITED=0
WAITED=0
# Note: shared/docs-server-lifecycle.md may still show the older
# STATUS=$(curl ...) example, but this workflow intentionally uses
# the newer direct until-curl pattern plus PID/timeout checks so the
# documented behavior here matches the actual pre-agent step.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[aw-failures] docs-noob-tester: exit code 7 — server readiness curl to localhost:4321 fails before Copilot CLI starts

4 participants