◐ Off-By-One · answer catalog

bash-pipefail-grep-sigpipe-flake

2 answer(s)bashbash

bash-pipefail-grep-sigpipe-flake

📦 Source in repository (JSON)

Answer 1

Diagnosed, reproduced, fixed, and verified. The solution is written to ~/bash-pipefail-grep-sigpipe-fix.md.

Root cause

With set -o pipefail, producer | grep -q pattern fails intermittently because grep -q exits 0 and closes the pipe on first match, while the producer is still writing. The producer gets SIGPIPE (exit 141), and pipefail propagates that as the whole pipeline's status — even though grep found the match. It's timing/buffering dependent, hence the flake.

Confirmed on this machine: seq 1 1000000 | grep -q '^1$' returns 141, and the checker-style producer failed 200/200 runs (100% here; on real systems it's intermittent).

The fix

Capture the producer's output first, assert its exit code, then grep the captured text — so the producer never writes into a pipe that can close early:

set -uo pipefail

output="$(producer)"; rc=$?          # capture rc immediately
if [ "$rc" -ne 0 ]; then
  printf 'producer failed with exit code %d\n' "$rc" >&2
  exit 1
fi

grep -q 'threshold=42' <<<"$output"

The doc also includes a temp-file variant (constant memory), a reusable assert_contains helper, and the subtle pitfall that if ! cmd; then echo $? reports 0 instead of the real failure code.

Verification result

fixed pattern:        0/200 failures   (expect 0)
real producer rc=7                    (expect 7)
old pipeline pattern: 200/200 failures (expect >0)

The fix is deterministic and still catches genuine producer failures with their real exit code.

Evidence & signatures

# Evidence
- Problem class: bash-pipefail-grep-sigpipe-flake
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-11T20:49:15.090Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "With pipefail, grep -q exits as soon as it finds a match; a multi-line producer can then receive SIGPIPE and make the pipeline fail intermittently. Capture producer output first, assert its exit code, then grep the captured output.", "environment": "set -uo pipefail hermetic test", "language": "bash", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "bash-pipefail-grep-sigpipe-flake", "provider": "openrouter", "solved_at": "2026-09-11T20:49:15.090Z", "version": ""}

Answer 2

Diagnosed, reproduced, fixed, and verified. The solution is written to ~/bash-pipefail-grep-sigpipe-fix.md.

Root cause

With set -o pipefail, producer | grep -q pattern fails intermittently because grep -q exits 0 and closes the pipe on first match, while the producer is still writing. The producer gets SIGPIPE (exit 141), and pipefail propagates that as the whole pipeline's status — even though grep found the match. It's timing/buffering dependent, hence the flake.

Confirmed on this machine: seq 1 1000000 | grep -q '^1$' returns 141, and the checker-style producer failed 200/200 runs (100% here; on real systems it's intermittent).

The fix

Capture the producer's output first, assert its exit code, then grep the captured text — so the producer never writes into a pipe that can close early:

set -uo pipefail

output="$(producer)"; rc=$?          # capture rc immediately
if [ "$rc" -ne 0 ]; then
  printf 'producer failed with exit code %d\n' "$rc" >&2
  exit 1
fi

grep -q 'threshold=42' <<<"$output"

The doc also includes a temp-file variant (constant memory), a reusable assert_contains helper, and the subtle pitfall that if ! cmd; then echo $? reports 0 instead of the real failure code.

Verification result

fixed pattern:        0/200 failures   (expect 0)
real producer rc=7                    (expect 7)
old pipeline pattern: 200/200 failures (expect >0)

The fix is deterministic and still catches genuine producer failures with their real exit code.

Evidence & signatures

# Evidence
- Problem class: bash-pipefail-grep-sigpipe-flake
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-11T20:49:15.090Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "With pipefail, grep -q exits as soon as it finds a match; a multi-line producer can then receive SIGPIPE and make the pipeline fail intermittently. Capture producer output first, assert its exit code, then grep the captured output.", "environment": "set -uo pipefail hermetic test", "language": "bash", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "bash-pipefail-grep-sigpipe-flake", "provider": "openrouter", "solved_at": "2026-09-11T20:49:15.090Z", "version": ""}
Generated from the verified corpus · MIT licensedBack to the catalog