Environment
- Supabase CLI 2.116.0 (npm
supabase, @supabase/cli-darwin-arm64); also observed on 2.118.0
- macOS 27.0 (26A428), Apple Silicon (arm64)
- Local stack running (
supabase start)
Steps to reproduce
npx supabase status 2>&1 | head -3
Expected
head prints three lines and exits; the CLI receives EPIPE/SIGPIPE on its next write and exits.
Actual
head exits, but the CLI process never does. It stays at 157-161% CPU until killed. sample shows the main thread looping in kevent64. Because the shell waits on every member of a pipeline, the command never completes. One background invocation ran for 14 hours before it was noticed.
Measurements (each run killed by a watchdog after 15-25 s)
| Command |
Result |
npx supabase status 2>&1 | head -3 |
hangs, 159.8% CPU after 24 s |
npx supabase status 2>&1 | grep -q Stopped |
hangs, 157.5% CPU |
node_modules/@supabase/cli-darwin-arm64/bin/supabase status 2>&1 | head -1 |
hangs, 161.2% CPU |
npx supabase status 2>/dev/null | head -3 |
exits 0 |
npx supabase status 2>&1 >/dev/null | head -1 |
exits 0 |
npx supabase status 2>&1 | cat >/dev/null |
exits 0 |
X=$(npx supabase status -o json 2>/dev/null) |
exits 0 |
The hang requires both stdout and stderr in the same pipe, with a reader that closes before the CLI has finished writing. Piping only one stream, or draining everything, exits normally. Setting SUPABASE_NO_UPDATE_NOTIFIER=1 does not change the result.
Suggested fix
Exit (or stop writing) when a write to stdout or stderr fails with EPIPE, rather than retrying in the event loop.
Workaround
Capture the whole output first (X=$(supabase status -o json 2>/dev/null)) or redirect to a file, then read that.
Environment
supabase,@supabase/cli-darwin-arm64); also observed on 2.118.0supabase start)Steps to reproduce
npx supabase status 2>&1 | head -3Expected
headprints three lines and exits; the CLI receives EPIPE/SIGPIPE on its next write and exits.Actual
headexits, but the CLI process never does. It stays at 157-161% CPU until killed.sampleshows the main thread looping inkevent64. Because the shell waits on every member of a pipeline, the command never completes. One background invocation ran for 14 hours before it was noticed.Measurements (each run killed by a watchdog after 15-25 s)
npx supabase status 2>&1 | head -3npx supabase status 2>&1 | grep -q Stoppednode_modules/@supabase/cli-darwin-arm64/bin/supabase status 2>&1 | head -1npx supabase status 2>/dev/null | head -3npx supabase status 2>&1 >/dev/null | head -1npx supabase status 2>&1 | cat >/dev/nullX=$(npx supabase status -o json 2>/dev/null)The hang requires both stdout and stderr in the same pipe, with a reader that closes before the CLI has finished writing. Piping only one stream, or draining everything, exits normally. Setting
SUPABASE_NO_UPDATE_NOTIFIER=1does not change the result.Suggested fix
Exit (or stop writing) when a write to stdout or stderr fails with EPIPE, rather than retrying in the event loop.
Workaround
Capture the whole output first (
X=$(supabase status -o json 2>/dev/null)) or redirect to a file, then read that.