Skip to content

hooks/BackupDynalist.py (Selenium script that logs into Dynalist and downloads a backup zip during the daily my_backup pre-backup hooks) started failing 2026-07-07 and 2026-07-08, both times at the same point: a WebDriverWait(driver, 10) timeout waiting for the post-login hamburger menu (AppHeader-mainMenu class) to become clickable, after email/password entry and sign-in click succeeded.

Confirmed via a live fetch of https://dynalist.io/login that the login-page selectors (EmailField, input[type=password], js-login button) were still valid — the break was specifically post-login, not the login form itself. Could not determine the exact cause (Dynalist DOM change vs. bot-detection block vs. silent login failure) from the WSL session that diagnosed this, since that page requires a live authenticated browser and WSL→Windows interop was down at the time (see 2026-07-08_web-deploy-focus-crash-and-wsl-interop.md — fixed later the same day, but not yet applied when this task started).

Rather than guess at a DOM/selector fix, the script was hardened so the next failure (if any) produces enough evidence to diagnose without re-running blind:

  1. Real bug fixed: except ValueError never caught Selenium’s TimeoutException/WebDriverException, so the script crashed with an unhandled traceback instead of failing cleanly. Broadened to except (ValueError, WebDriverException).
  2. Added failure diagnostics: on any caught WebDriverException, the script now saves a screenshot, full page source, and current URL/title to logs/dynalist_debug/failure_<timestamp>.*.
  3. Security hygiene: moved the hardcoded plaintext EMAIL/PASSWORD out of source into .env (DYNALIST_EMAIL, DYNALIST_PASSWORD), matching the PROJECT_ROOT + load_dotenv() pattern already used by every script in src/my_backup/.

The 2026-07-09 08:00 scheduled run succeeded ([OK] Dynalist Capture in backup.log; fresh dynalist-backup.zip written; no dynalist_debug/ artifacts) — Talbot confirmed “working again.” Whatever caused the two-day outage was transient (or WSL interop being down was somehow a factor in how it was first investigated, not in the actual failure) — it did not recur once the exception-handling bug was fixed, so no DOM/selector change was ultimately needed.

  • hooks/BackupDynalist.py — broadened exception handling, added failure-diagnostic capture, moved credentials to .env
  • .env — added DYNALIST_EMAIL / DYNALIST_PASSWORD (gitignored, not committed)
  • A narrow except ValueError around Selenium code silently swallows nothing and catches nothing useful — Selenium raises WebDriverException subclasses (TimeoutException, etc.), never ValueError. Any Selenium hook script needs except (ValueError, WebDriverException) or broader, or failures crash unhandled with no clean error path.
  • When a Selenium-based scraper against a third-party site fails, don’t guess at a new selector — capture forensic evidence on failure instead (screenshot + page source + URL to a debug folder). Third-party UI changes, anti-bot blocks, and silent auth failures all look identical from a log line alone; only the captured page state tells them apart.
  • A WSL Claude session cannot verify Windows-native Selenium/browser scripts live — no local Chrome, and WSL→Windows interop may be unavailable (as it was here, until fixed by an unrelated task the same day). Diagnose from logs, make closely-scoped code fixes, and ask the user to trigger one real run rather than guessing.