Skip to content

fix: prevent postinstall infinite loop on bun install#1064

Merged
Kitenite merged 1 commit intosuperset-sh:mainfrom
spanishflu-est1918:fix/postinstall-infinite-loop
Jan 31, 2026
Merged

fix: prevent postinstall infinite loop on bun install#1064
Kitenite merged 1 commit intosuperset-sh:mainfrom
spanishflu-est1918:fix/postinstall-infinite-loop

Conversation

@spanishflu-est1918
Copy link
Copy Markdown
Contributor

@spanishflu-est1918 spanishflu-est1918 commented Jan 30, 2026

Summary

  • Fixes the infinite process spawn loop during bun install
  • Adds environment variable guard to prevent recursive postinstall invocations

Problem

When running bun install, the postinstall script spawns 370+ electron-builder install-app-deps processes in an infinite loop, causing the install to never complete.

Root cause: electron-builder install-app-deps triggers nested bun installs which re-run postinstall, creating a recursive loop.

Solution

Created a scripts/postinstall.sh wrapper that:

  1. Checks for SUPERSET_POSTINSTALL_RUNNING environment variable
  2. Exits early if already in a postinstall run
  3. Sets the guard variable before running the actual postinstall commands

Test plan

  • Run bun install from a clean clone - should complete without hanging
  • Run bun run build - should build the desktop app successfully
  • Verify native modules (better-sqlite3, node-pty) are properly compiled

Fixes #1063

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed postinstall script to prevent recursive execution, ensuring installation runs exactly once and completes reliably.
  • Chores

    • Reorganized installation script structure for improved maintainability and clarity during the package setup process.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 30, 2026

📝 Walkthrough

Walkthrough

The postinstall script in package.json is refactored from an inline command into an external shell script that includes a recursion guard using an environment variable to prevent infinite re-invocation of electron-builder processes during installation.

Changes

Cohort / File(s) Summary
Postinstall Script Refactor
package.json
Modified scripts.postinstall entry to invoke ./scripts/postinstall.sh instead of executing chained commands directly.
Recursion Guard Implementation
scripts/postinstall.sh
New shell script with SUPERSET_POSTINSTALL_RUNNING guard to prevent recursive execution, followed by sherif validation and bun-based desktop dependency installation.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 A rabbit hops through the install once,
No infinite loops or circular stunts!
The guard flag stands tall, preventing recursion,
Building from source is now a smooth excursion!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main fix: preventing an infinite loop in the postinstall script during bun install, which directly addresses the primary change in the PR.
Description check ✅ Passed The description includes a clear summary, problem statement, solution explanation, and test plan. It follows the template structure with well-organized sections and actionable information.
Linked Issues check ✅ Passed The PR successfully implements the first suggested fix from issue #1063 by adding an environment variable guard (SUPERSET_POSTINSTALL_RUNNING) to prevent recursive postinstall invocations, directly addressing the infinite loop problem.
Out of Scope Changes check ✅ Passed All changes are strictly within scope: the postinstall script modification and the new guard script directly address the infinite loop issue described in issue #1063 with no unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

The postinstall script was spawning hundreds of electron-builder
processes in an infinite loop. This happened because:

1. postinstall runs `bun run --filter=@superset/desktop install:deps`
2. install:deps runs `electron-builder install-app-deps`
3. electron-builder triggers nested bun installs
4. Those installs re-trigger postinstall, repeating the cycle

This fix adds an environment variable guard to detect and prevent
recursive postinstall invocations.

Fixes superset-sh#1063

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@scripts/postinstall.sh`:
- Around line 1-16: Enable strict shell error handling at the top of the script
so failures in sherif or the bun command abort the postinstall: add POSIX-safe
strict mode (set -euo pipefail) before any commands that can fail, keep the
SUPERSET_POSTINSTALL_RUNNING guard and export as-is, and ensure sherif and the
bun install line run under that strict mode so any non-zero exit will terminate
the script immediately.

Comment thread scripts/postinstall.sh
Comment on lines +1 to +16
#!/bin/bash
# Prevent infinite recursion during postinstall
# electron-builder install-app-deps can trigger nested bun installs
# which would re-run postinstall, spawning hundreds of processes

if [ -n "$SUPERSET_POSTINSTALL_RUNNING" ]; then
exit 0
fi

export SUPERSET_POSTINSTALL_RUNNING=1

# Run sherif for workspace validation
sherif

# Install native dependencies for desktop app
bun run --filter=@superset/desktop install:deps
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🌐 Web query:

bash strict mode set -e set -u set -o pipefail best practices error handling

💡 Result:

What “strict mode” does (and what it doesn’t)

Common pattern:

set -euo pipefail
  • set -e (errexit): exit when an unhandled command fails, but it is intentionally skipped in several contexts (tests in if/while/until, most &&/|| lists, non-last pipeline elements unless pipefail, and when status is inverted with !). So you still need explicit checks where you expect failures. [2]
  • set -u (nounset): treat unset variables as an error. [1]
  • set -o pipefail: a pipeline fails if any element fails (specifically: returns the last non‑zero status, or 0 if all succeed). Disabled by default. [1]

Best-practice pattern (robust + debuggable errors)

1) Prefer explicit error handling + a trap, not blind reliance on set -e

Use a single error handler that prints context:

#!/usr/bin/env bash
set -Eeuo pipefail

die() { echo "ERROR: $*" >&2; exit 1; }
trap 'die "Command failed (exit=$?) at ${BASH_SOURCE[0]}:${LINENO}: ${BASH_COMMAND}"' ERR

Why -E? It helps ERR traps propagate into functions/subshell contexts (without it, you’ll miss failures in places you thought were covered). [2]

2) When failure is expected, handle it explicitly

Under -e, don’t “probe” with commands that might fail unless you capture/branch on the status:

grep -q pattern file || echo "not found (this is ok)"
# or
if ! grep -q pattern file; then
  echo "not found"
fi

This aligns with “always check return values” guidance. [3]

3) Be careful with pipefail + early-terminating consumers (head, grep -q)

With pipefail, producers can die with SIGPIPE when the downstream command exits early; that can abort your script even though the overall behavior is fine. You may need to explicitly allow it, or restructure:

# allow SIGPIPE-ish failures if you truly don’t care:
set +e
big_producer | head -n 1
set -e

(Or avoid such pipelines / use tools designed for it.)

4) Avoid “hidden” errexit holes ShellCheck warns about

Example: ! cmd can suppress errexit unexpectedly unless you explicitly exit/check status. [4]

set -e
! some_check || exit 1

5) If you need POSIX sh, don’t use pipefail

pipefail is not POSIX; either require bash, or implement an alternative. [5]


Key takeaway

set -euo pipefail is a good baseline, but robust Bash comes from: (a) explicit checks where failure is expected, (b) an ERR trap for actionable diagnostics, and (c) knowing the documented contexts where errexit/pipefail don’t behave like exceptions. [1][2][3]

Sources: GNU Bash manual for pipefail/nounset and errexit/ERR-trap exceptions [1][2], Google Shell Style Guide on checking return values and error reporting [3], ShellCheck wiki on ! vs errexit and portability of pipefail [4][5].


🏁 Script executed:

# First, let's see the full postinstall.sh file to understand the complete context
cat -n scripts/postinstall.sh

Repository: superset-sh/superset

Length of output: 609


🏁 Script executed:

# Let's check if there are other bash scripts in the repo to see patterns for error handling
fd -e sh -e bash . --type f | head -20

Repository: superset-sh/superset

Length of output: 205


🏁 Script executed:

# Check if postinstall.sh is referenced in package.json or other build configs
rg -i "postinstall" --max-count 10

Repository: superset-sh/superset

Length of output: 653


🏁 Script executed:

# Check if other scripts in the same location use set -e or strict mode
head -5 scripts/lint.sh

Repository: superset-sh/superset

Length of output: 204


🏁 Script executed:

# Check the desktop build script for comparison
head -10 apps/desktop/create-release.sh

Repository: superset-sh/superset

Length of output: 407


Fail fast on sherif/bun errors (enable strict mode).

Without set -e (and ideally -u -o pipefail), a failed sherif command will not terminate the script, allowing subsequent commands to execute even after validation fails. Since this script runs as an npm/bun postinstall hook, such failures should halt the installation. Add strict mode to catch errors early.

♻️ Proposed change
 #!/bin/bash
+set -euo pipefail
+
 # Prevent infinite recursion during postinstall
 # electron-builder install-app-deps can trigger nested bun installs
 # which would re-run postinstall, spawning hundreds of processes
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#!/bin/bash
# Prevent infinite recursion during postinstall
# electron-builder install-app-deps can trigger nested bun installs
# which would re-run postinstall, spawning hundreds of processes
if [ -n "$SUPERSET_POSTINSTALL_RUNNING" ]; then
exit 0
fi
export SUPERSET_POSTINSTALL_RUNNING=1
# Run sherif for workspace validation
sherif
# Install native dependencies for desktop app
bun run --filter=@superset/desktop install:deps
#!/bin/bash
set -euo pipefail
# Prevent infinite recursion during postinstall
# electron-builder install-app-deps can trigger nested bun installs
# which would re-run postinstall, spawning hundreds of processes
if [ -n "$SUPERSET_POSTINSTALL_RUNNING" ]; then
exit 0
fi
export SUPERSET_POSTINSTALL_RUNNING=1
# Run sherif for workspace validation
sherif
# Install native dependencies for desktop app
bun run --filter=@superset/desktop install:deps
🤖 Prompt for AI Agents
In `@scripts/postinstall.sh` around lines 1 - 16, Enable strict shell error
handling at the top of the script so failures in sherif or the bun command abort
the postinstall: add POSIX-safe strict mode (set -euo pipefail) before any
commands that can fail, keep the SUPERSET_POSTINSTALL_RUNNING guard and export
as-is, and ensure sherif and the bun install line run under that strict mode so
any non-zero exit will terminate the script immediately.

Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite left a comment

Choose a reason for hiding this comment

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

I can't consistently reproduce it but since this is a harmless/reversible change that doesn't affect behavior I can merge. Thanks @spanishflu-est1918

@Kitenite Kitenite merged commit 9d5e27e into superset-sh:main Jan 31, 2026
1 check passed
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.

Build from source: postinstall spawns infinite electron-builder processes

2 participants