Skip to content

Commit a9ca20e

Browse files
committed
Fix false exit-code-1 in terminal and improve error handling
main.js: - Remove pre-flight sendProcessError check that was firing code 1 before any process started (fs.existsSync check could fail on Windows even when file exists, e.g. case sensitivity or path format issues) - Add _userStopped flag so Stop button on Windows (which kills with exit code 1) is reported as null (stopped) not an error in the renderer - Apply _userStopped to both pty and pipe-mode close/exit handlers Python scripts (downloader, extract_caption, semantic_alignment, note_generation): - Wrap main() call in broad try/except to catch all unhandled runtime exceptions, print a clear [error] message + traceback, and exit 1 (instead of bare Python traceback with no context) - KeyboardInterrupt exits cleanly with code 0
1 parent 813fcc3 commit a9ca20e

5 files changed

Lines changed: 68 additions & 33 deletions

File tree

downloader.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1266,4 +1266,15 @@ def main() -> None:
12661266

12671267

12681268
if __name__ == "__main__":
1269-
main()
1269+
try:
1270+
main()
1271+
except KeyboardInterrupt:
1272+
print("\n[info] Interrupted by user.")
1273+
sys.exit(0)
1274+
except SystemExit:
1275+
raise
1276+
except Exception as _exc:
1277+
import traceback
1278+
print(f"\n[error] Unexpected error: {_exc}")
1279+
traceback.print_exc()
1280+
sys.exit(1)

electron/main.js

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -337,37 +337,15 @@ function torchIndexUrl(cuda) {
337337
}
338338

339339
// ── Active process state ──────────────────────────────────────────────────────
340-
let activeProc = null;
341-
let installProc = null;
342-
let mainWindow = null;
340+
let activeProc = null;
341+
let installProc = null;
342+
let mainWindow = null;
343+
let _userStopped = false; // set true when user clicks Stop, so close code is ignored
343344

344345
// ── Subprocess runner (pipeline scripts) ─────────────────────────────────────
345-
function sendProcessError(msg) {
346-
mainWindow?.webContents.send('process:data', msg + '\n');
347-
mainWindow?.webContents.send('process:done', { code: 1 });
348-
}
349-
350346
function runProcess(cmd) {
351347
if (activeProc) return { error: 'Already running — stop it first.' };
352-
353-
// ── Pre-flight validation ──────────────────────────────────────────────────
354-
const [pythonExe, scriptFile] = cmd;
355-
356-
// Validate Python executable: if it looks like an absolute path, check it exists.
357-
if (pythonExe && path.isAbsolute(pythonExe) && !fs.existsSync(pythonExe)) {
358-
sendProcessError(
359-
`[error] Python executable not found: ${pythonExe}\n` +
360-
`[error] Please install the ML environment from Settings → ML Environment,\n` +
361-
`[error] or configure a valid Python path in Settings → Connection.`
362-
);
363-
return { ok: true };
364-
}
365-
366-
// Validate script file exists.
367-
if (scriptFile && path.isAbsolute(scriptFile) && !fs.existsSync(scriptFile)) {
368-
sendProcessError(`[error] Script not found: ${scriptFile}`);
369-
return { ok: true };
370-
}
348+
_userStopped = false;
371349

372350
const outDir = getOutputDir();
373351
fs.mkdirSync(outDir, { recursive: true });
@@ -395,7 +373,11 @@ function runProcess(cmd) {
395373
});
396374
ptyProc.onExit(({ exitCode }) => {
397375
activeProc = null;
398-
mainWindow?.webContents.send('process:done', { code: exitCode });
376+
if (_userStopped) {
377+
mainWindow?.webContents.send('process:done', { code: null });
378+
} else {
379+
mainWindow?.webContents.send('process:done', { code: exitCode });
380+
}
399381
});
400382
return { ok: true };
401383
} catch { /* fall through to pipe mode */ }
@@ -413,9 +395,15 @@ function runProcess(cmd) {
413395
proc.stderr.on('data', d => mainWindow?.webContents.send('process:data', d.toString('utf8')));
414396
proc.on('close', code => {
415397
activeProc = null;
416-
mainWindow?.webContents.send('process:done', { code });
398+
if (_userStopped) {
399+
// User clicked Stop — don't treat as an error regardless of exit code
400+
mainWindow?.webContents.send('process:done', { code: null });
401+
} else {
402+
mainWindow?.webContents.send('process:done', { code: code ?? 1 });
403+
}
417404
});
418405
proc.on('error', err => {
406+
if (_userStopped) { activeProc = null; return; }
419407
activeProc = null;
420408
const hint = err.code === 'ENOENT'
421409
? `\n[error] Could not find executable: ${prog}\n[error] Install the ML environment from Settings → ML Environment.`
@@ -428,11 +416,14 @@ function runProcess(cmd) {
428416

429417
function stopProcess() {
430418
if (!activeProc) return;
419+
_userStopped = true;
431420
try {
432421
if (typeof activeProc.kill === 'function') activeProc.kill();
433422
else activeProc.kill('SIGTERM');
434423
} catch {}
435424
activeProc = null;
425+
// Send 'stopped' event immediately so the renderer doesn't wait for close
426+
mainWindow?.webContents.send('process:done', { code: null });
436427
}
437428

438429
// ── ML environment installer ──────────────────────────────────────────────────

extract_caption.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,4 +431,15 @@ def main() -> None:
431431

432432

433433
if __name__ == "__main__":
434-
main()
434+
try:
435+
main()
436+
except KeyboardInterrupt:
437+
print("\n[info] Interrupted by user.")
438+
sys.exit(0)
439+
except SystemExit:
440+
raise
441+
except Exception as _exc:
442+
import traceback
443+
print(f"\n[error] Unexpected error: {_exc}")
444+
traceback.print_exc()
445+
sys.exit(1)

note_generation.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1394,4 +1394,15 @@ def main() -> None:
13941394

13951395

13961396
if __name__ == "__main__":
1397-
main()
1397+
try:
1398+
main()
1399+
except KeyboardInterrupt:
1400+
print("\n[info] Interrupted by user.")
1401+
sys.exit(0)
1402+
except SystemExit:
1403+
raise
1404+
except Exception as _exc:
1405+
import traceback
1406+
print(f"\n[error] Unexpected error: {_exc}")
1407+
traceback.print_exc()
1408+
sys.exit(1)

semantic_alignment.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1189,4 +1189,15 @@ def main() -> None:
11891189

11901190

11911191
if __name__ == "__main__":
1192-
main()
1192+
try:
1193+
main()
1194+
except KeyboardInterrupt:
1195+
print("\n[info] Interrupted by user.")
1196+
sys.exit(0)
1197+
except SystemExit:
1198+
raise
1199+
except Exception as _exc:
1200+
import traceback
1201+
print(f"\n[error] Unexpected error: {_exc}")
1202+
traceback.print_exc()
1203+
sys.exit(1)

0 commit comments

Comments
 (0)