Severity: P2
Surfaced by: review of #5
Several error paths in auth.py and cli.py either swallow errors silently or surface as raw tracebacks, making the CLI hostile to autonomous orchestrators and humans alike.
1. cli.py login command not wrapped (cli.py:28-31)
Other CLI commands wrap their body in try/except, print Error: {e} to stderr, exit 1. The login command calls auth.login() bare. A TimeoutError, PlaywrightError (browser binary missing, no DISPLAY, persistent context locked by a concurrent run), or OSError bubbles up as an uncaught traceback. An orchestrator agent watching exit code + stderr cannot distinguish "human didn't log in within 5 minutes" from "playwright not installed" from "no DISPLAY".
Fix: wrap auth.login() with distinct exit codes per failure class. Suggested mapping:
TimeoutError → stderr "Login timed out: …" + exit 2
PlaywrightError → stderr "Browser launch failed: …" + exit 3
- generic → exit 1
2. Polling loop unprotected from page/context closure (auth.py:96-103)
If the user closes the browser window mid-poll, page.url raises PlaywrightError("Target page, context or browser has been closed"). It escapes through finally, where context.close() against a dead context may also throw, masking the original cause. Result: stack trace instead of "browser closed before login completed".
Fix: wrap page.url access in try/except PlaywrightError, translate to a clear RuntimeError.
3. context.close() in finally can mask original exception (auth.py:77-78)
If both the try block and close() raise, Python replaces the original exception in the traceback (it survives only as __context__). Diagnosis becomes harder.
Fix: wrap context.close() in its own try/except that logs and discards close-time errors.
4. load_browser_cookies swallows OSError silently (auth.py:27-30)
Permission errors, I/O errors, JSON corruption all collapse to []. The caller cannot distinguish "never logged in" from "cookie file unreadable due to permissions".
Fix: narrow except to json.JSONDecodeError; let OSError propagate, or at least print before returning [].
Severity: P2
Surfaced by: review of #5
Several error paths in
auth.pyandcli.pyeither swallow errors silently or surface as raw tracebacks, making the CLI hostile to autonomous orchestrators and humans alike.1.
cli.pylogincommand not wrapped (cli.py:28-31)Other CLI commands wrap their body in
try/except, printError: {e}to stderr, exit 1. Thelogincommand callsauth.login()bare. ATimeoutError,PlaywrightError(browser binary missing, no DISPLAY, persistent context locked by a concurrent run), orOSErrorbubbles up as an uncaught traceback. An orchestrator agent watching exit code + stderr cannot distinguish "human didn't log in within 5 minutes" from "playwright not installed" from "no DISPLAY".Fix: wrap
auth.login()with distinct exit codes per failure class. Suggested mapping:TimeoutError→ stderr "Login timed out: …" + exit 2PlaywrightError→ stderr "Browser launch failed: …" + exit 32. Polling loop unprotected from page/context closure (
auth.py:96-103)If the user closes the browser window mid-poll,
page.urlraisesPlaywrightError("Target page, context or browser has been closed"). It escapes throughfinally, wherecontext.close()against a dead context may also throw, masking the original cause. Result: stack trace instead of "browser closed before login completed".Fix: wrap
page.urlaccess intry/except PlaywrightError, translate to a clearRuntimeError.3.
context.close()infinallycan mask original exception (auth.py:77-78)If both the try block and
close()raise, Python replaces the original exception in the traceback (it survives only as__context__). Diagnosis becomes harder.Fix: wrap
context.close()in its own try/except that logs and discards close-time errors.4.
load_browser_cookiesswallowsOSErrorsilently (auth.py:27-30)Permission errors, I/O errors, JSON corruption all collapse to
[]. The caller cannot distinguish "never logged in" from "cookie file unreadable due to permissions".Fix: narrow
excepttojson.JSONDecodeError; letOSErrorpropagate, or at least print before returning[].