What happened
After a --fast TWIC import hit a fatal DuckDB error, the database entered DuckDB's invalidated state ("database has been invalidated because of a previous fatal error … must be restarted prior to being used again"). The raw error string then surfaced verbatim in the Home screen's "Automatic updates" panel, e.g.:
Error: FATAL Error: Failed: database has been invalidated because of a previous fatal error. … Original error: "Invalid Input Error: Failed to delete all rows from index. Only deleted 0 out of 1 rows. …"
A sudo systemctl restart lpdo-server fully recovered it (on-disk DB intact — the failed work rolled back on reopen).
Ask
Detect the server-fatal / DB-invalidated state and present a clean recovery card ("The server hit a database error and needs to restart") with a clear action — instead of dumping the raw DuckDB message into a random panel. The error also shouldn't leak into the "Automatic updates" (scheduler/status) section as a raw string; that panel should render a tidy error state.
Design notes
- A "Restart server" button is non-trivial for a system daemon (privileged):
sudo systemctl restart lpdo-server (Linux), launchctl kickstart -k system/com.specure.lpdo.server (macOS), sc stop/start LPDOServer (Windows) all need elevation the GUI doesn't have. Options, best first:
- Server-side auto-recovery (preferred): catch DuckDB's "invalidated / must be restarted" error in
serve.rs/jobs.rs and reopen the DB connection in-process (new Connection) so it self-heals with no user action and no OS restart. The user never sees this.
- A
/restart endpoint the GUI can call (daemon re-execs, or exits with the unit set to Restart=always).
- GUI shows the platform-specific restart command for the user to run (no in-GUI privilege). Lowest effort, worst UX.
- Detect the state from
/status (and other endpoints) returning the fatal/invalidated error, and switch the whole app into the recovery state rather than rendering per-panel raw strings.
Related (separate, deeper — root cause)
The --fast import is appender-based and not crash-safe, so a mid-write failure (here: Failed to delete all rows from index on a player row) can drop the DB into the invalidated state. Worth its own issue: (a) why the fast-import index op failed (DuckDB ART index / dedup interaction, possibly version-specific), and (b) making the import fail more gracefully (transactional, or checkpoint/guard) so it can't invalidate the live DB. Combined with the auto-recovery above, the user would never hit a dead server.
What happened
After a
--fastTWIC import hit a fatal DuckDB error, the database entered DuckDB's invalidated state ("database has been invalidated because of a previous fatal error … must be restarted prior to being used again"). The raw error string then surfaced verbatim in the Home screen's "Automatic updates" panel, e.g.:A
sudo systemctl restart lpdo-serverfully recovered it (on-disk DB intact — the failed work rolled back on reopen).Ask
Detect the server-fatal / DB-invalidated state and present a clean recovery card ("The server hit a database error and needs to restart") with a clear action — instead of dumping the raw DuckDB message into a random panel. The error also shouldn't leak into the "Automatic updates" (scheduler/status) section as a raw string; that panel should render a tidy error state.
Design notes
sudo systemctl restart lpdo-server(Linux),launchctl kickstart -k system/com.specure.lpdo.server(macOS),sc stop/start LPDOServer(Windows) all need elevation the GUI doesn't have. Options, best first:serve.rs/jobs.rsand reopen the DB connection in-process (newConnection) so it self-heals with no user action and no OS restart. The user never sees this./restartendpoint the GUI can call (daemon re-execs, or exits with the unit set toRestart=always)./status(and other endpoints) returning the fatal/invalidated error, and switch the whole app into the recovery state rather than rendering per-panel raw strings.Related (separate, deeper — root cause)
The
--fastimport is appender-based and not crash-safe, so a mid-write failure (here:Failed to delete all rows from indexon a player row) can drop the DB into the invalidated state. Worth its own issue: (a) why the fast-import index op failed (DuckDB ART index / dedup interaction, possibly version-specific), and (b) making the import fail more gracefully (transactional, or checkpoint/guard) so it can't invalidate the live DB. Combined with the auto-recovery above, the user would never hit a dead server.