From f3b809624adc6579778e4be9cb0d2b538efa3930 Mon Sep 17 00:00:00 2001 From: Gergo Magyar Date: Sun, 21 Jun 2026 07:41:50 +0000 Subject: [PATCH] fix(lbug): real close on the analyze error path to avoid a hang under skipNativeClose (#2264 review P1-2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CLI error handler soft-returns (process.exitCode = 1) instead of forcing exit, relying on the released native handles to let Node terminate. The earlier commit made runFullAnalysis's error-path closeLbug skip the native close, leaving live LadybugDB handles that keep the event loop alive forever — a post-init analyze failure would hang. Only the SUCCESS path (which guarantees a following process.exit) skips the native close; the error path now always closes for real. A late-error close could still abort in the destructor, but that terminates the process — it does not hang. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01JBJomjoTdBV2eveDVq4JMm --- gitnexus/src/core/run-analyze.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/gitnexus/src/core/run-analyze.ts b/gitnexus/src/core/run-analyze.ts index e3edc4335..f4387b709 100644 --- a/gitnexus/src/core/run-analyze.ts +++ b/gitnexus/src/core/run-analyze.ts @@ -1582,9 +1582,14 @@ export async function runFullAnalysis( /* swallow — surface path is the rethrow below */ } try { - // Same native-close skip on the error path for CLI callers — they - // process.exit too, and the native close can double-free (#2264). - await closeLbug({ skipNativeClose: options.skipNativeCloseOnExit }); + // Real close on the error path — NOT skipNativeClose. The CLI error + // handler soft-returns (process.exitCode = 1) instead of forcing exit, so + // the native handles must be released here or the process would hang on the + // live connection (#2264 review P1-2). A late-error close could still abort + // in LadybugDB's destructor, but that terminates the process — it does not + // hang. Only the success path (which guarantees a following process.exit) + // skips the native close. + await closeLbug(); } catch { /* swallow */ }