Skip to content

Fix ERR_USE_AFTER_CLOSE crash on Node 24+ with non-interactive stdin - #163

Merged
githubsaturn merged 2 commits into
caprover:masterfrom
ivnnv:fix-readline-node24
Aug 29, 2026
Merged

Fix ERR_USE_AFTER_CLOSE crash on Node 24+ with non-interactive stdin#163
githubsaturn merged 2 commits into
caprover:masterfrom
ivnnv:fix-readline-node24

Conversation

@ivnnv

@ivnnv ivnnv commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Fixes #162. caprover api and caprover deploy crashed with ERR_USE_AFTER_CLOSE on Node 24 and newer whenever stdin isnt a TTY, so CI runs and deploy scripts died with a readline stack trace and exit 1. Node 20 and 22 are fine, bun 1.4 breaks the same way. The bump to inquirer ^10.2.2 is what fixes it: 6, 7, 8 and 9 all have the broken teardown and 10.0.0 is the first release without it. 10.x still ships a CommonJS build so this doesnt repeat the ESM-only breakage of 2.4.0, and @types/inquirer goes away because inquirer ships its own types now. IOption stops extending inquirer's question type, which moved and narrowed between 6 and 10, and declares the fields the CLI actually uses instead.

Second commit stops processParams() handing options to inquirer.prompt() when their when is false, since inquirer builds a readline interface per call even for a question it then skips. I verified the two independiently and either one on its own fixes the reported crash, but its small and part of the same thing so I kept it as one PR. Checked on Node 20.19, 22.22, 24.16, 26.2 and bun 1.4 against a live CapRover machine: non-interactive api calls, the interactive input and confirm path, the machine list prompt, and the masked password prompt.

Summary by CodeRabbit

  • Dependency Updates

    • Updated the interactive prompt experience to use the latest supported prompt library.
    • Removed the obsolete prompt-library type package.
  • Improvements

    • Improved handling of conditional prompts, ensuring questions are displayed only when applicable.
    • Preserved support for defaults, choices, filtering, and validation in command prompts.

ivnnv added 2 commits August 27, 2026 18:50
inquirer 6 tears a prompt down with rl.output.end(), rl.pause(), rl.close().
When stdin is not a TTY (/dev/null, a closed pipe, CI) the readline interface
receives "end" and closes itself first, so pause() runs on an already-closed
interface. Node 24 made that throw ERR_USE_AFTER_CLOSE, so every authenticated
command (api, deploy) dies with a stack trace and exit 1. Node 20 and 22
ignored the call. bun 1.4 behaves like Node 24.

inquirer 6, 7, 8 and 9 all have the teardown bug; 10.0.0 is the first release
without it. 10.x still ships a CommonJS build, so this does not repeat the
ESM-only breakage of 2.4.0.

IOption no longer extends inquirer's question type, which moved and narrowed
between 6 and 10, and declares the fields the CLI actually uses instead.
@types/inquirer is dropped because inquirer ships its own types.

Verified against a live CapRover machine on Node 20.19, 22.22, 24.16, 26.2 and
bun 1.4: non-interactive api calls, the interactive input/confirm path, the
machine list prompt, and the masked password prompt.
processParams() handed every option to inquirer.prompt(), including the ones whose "when" resolves to false. inquirer builds a readline interface per prompt() call even when it goes on to skip the question, so the CLI was creating and tearing down an interface per skipped option on every run. That teardown is exactly where ERR_USE_AFTER_CLOSE came from before the inquirer upgrade.

Resolve "when" before calling inquirer and skip the call when it is false. Behaviour is unchanged: prompt() is always called with a single option, so the answers hash passed to "when" is always empty either way.
@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a533cc06-1d6f-425f-9500-375eeaf06554

📥 Commits

Reviewing files that changed from the base of the PR and between 9ead4ef and b24fd9f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • package.json
  • src/commands/Command.ts

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Changes

Inquirer migration

Layer / File(s) Summary
Inquirer dependency and option contract
package.json, src/commands/Command.ts
Inquirer is upgraded to ^10.2.2. The separate type package is removed. IOption defines its prompt fields explicitly, and the import uses the module default.
Conditional prompt execution
src/commands/Command.ts
getParams resolves when before prompting and invokes Inquirer only when the option should be requested.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to b24fd

This PR upgrades Inquirer and avoids initializing skipped prompts, preventing the reported non-interactive stdin crash while preserving existing command parameter and validation flows. No actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: githubsaturn

Sequence Diagram(s)

sequenceDiagram
  participant getParams
  participant whenCondition
  participant inquirer
  getParams->>whenCondition: resolve the when condition
  whenCondition-->>getParams: return shouldAsk
  alt shouldAsk is true
    getParams->>inquirer: prompt the option with when=true
    inquirer-->>getParams: return the prompt result
  end
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 1 files. (1 skipped: 1 … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary change: fixing ERR_USE_AFTER_CLOSE crashes on Node 24 and newer when stdin is non-interactive.
Description check ✅ Passed The description clearly explains the issue, affected environments, implementation changes, compatibility considerations, and validation performed. It does not repeat the repository template boilerplat…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description clearly explains the issue, affected environments, implementation changes, compatibility considerations, and validation performed. It does not repeat the repository template boilerplate or confirm Slack communication, but the substantive information is complete.

Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 1 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@githubsaturn
githubsaturn merged commit 3a7ccfd into caprover:master Aug 29, 2026
3 checks 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.

caprover api/deploy crash with ERR_USE_AFTER_CLOSE on Node 24+ when stdin is not a TTY

2 participants