Skip to content

Fix bash 3.2 empty-array crash that aborts hooks under set -u#223

Open
chhzh123 wants to merge 1 commit into
PolyArch:mainfrom
chhzh123:fix/bash32-empty-array-hook-crash
Open

Fix bash 3.2 empty-array crash that aborts hooks under set -u#223
chhzh123 wants to merge 1 commit into
PolyArch:mainfrom
chhzh123:fix/bash32-empty-array-hook-crash

Conversation

@chhzh123

@chhzh123 chhzh123 commented Jul 9, 2026

Copy link
Copy Markdown

On macOS (bash 3.2.57, the system default) expanding a bare "${arr[@]}" on an empty array under set -u is a fatal "unbound variable" error, not the no-op it is on bash >= 4.4. The RLCR hooks run under set -euo pipefail and source these files, so that abort exits the hook with a non-zero, non-blocking status and no stderr -- surfaced by Claude Code as "Stop hook error: Failed with non-blocking status code: No stderr output", firing on every Stop-hook invocation.

Two empty-able array expansions hit this:

  • hooks/lib/template-loader.sh: render_template() runs env "${env_vars[@]}" awk ...; env_vars is empty for every static block/status/completion message (no substitution vars), so the Stop hook crashed before Codex even ran.
  • hooks/loop-codex-stop-hook.sh: CODEX_DISABLE_HOOKS_ARGS is initialized empty and only filled when the installed Codex CLI supports --disable; on older Codex builds it stays empty, so the codex review/codex exec invocations crashed the same way.

Guard each with the portable ${arr[@]+"${arr[@]}"} idiom (expand to the quoted elements when non-empty, to nothing when empty), correct on bash 3.2 and >= 4.4 alike. Other "${arr[@]}" expansions in the hooks iterate hardcoded non-empty literals and are unaffected.

Reproduced on /bin/bash 3.2.57:

  set -euo pipefail; a=(); env "${a[@]}" true         # -> a[@]: unbound variable (exit 1)
  set -euo pipefail; a=(); env ${a[@]+"${a[@]}"} true # -> ok (exit 0)

On macOS (bash 3.2.57, the system default) expanding a bare `"${arr[@]}"` on an
empty array under `set -u` is a fatal "unbound variable" error, not the no-op it
is on bash >= 4.4. The RLCR hooks run under `set -euo pipefail` and source these
files, so that abort exits the hook with a non-zero, non-blocking status and no
stderr -- surfaced by Claude Code as "Stop hook error: Failed with non-blocking
status code: No stderr output", firing on every Stop-hook invocation.

Two empty-able array expansions hit this:

- hooks/lib/template-loader.sh: render_template() runs
  `env "${env_vars[@]}" awk ...`; env_vars is empty for every static
  block/status/completion message (no substitution vars), so the Stop hook
  crashed before Codex even ran.
- hooks/loop-codex-stop-hook.sh: CODEX_DISABLE_HOOKS_ARGS is initialized empty
  and only filled when the installed Codex CLI supports `--disable`; on older
  Codex builds it stays empty, so the `codex review`/`codex exec` invocations
  crashed the same way.

Guard each with the portable `${arr[@]+"${arr[@]}"}` idiom (expand to the quoted
elements when non-empty, to nothing when empty), correct on bash 3.2 and >= 4.4
alike. Other `"${arr[@]}"` expansions in the hooks iterate hardcoded non-empty
literals and are unaffected.

Reproduced on /bin/bash 3.2.57:
  set -euo pipefail; a=(); env "${a[@]}" true         # -> a[@]: unbound variable (exit 1)
  set -euo pipefail; a=(); env ${a[@]+"${a[@]}"} true # -> ok (exit 0)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant