Skip and log unreadable pane trees during tab restore#9979
Skip and log unreadable pane trees during tab restore#9979amriksingh0786 wants to merge 1 commit intowarpdotdev:masterfrom
Conversation
`read_sqlite_data` used `filter_map(read_root_node(...).ok()?)` so a single tab whose pane tree failed to deserialize silently dropped every remaining tab in the same window. The 2026-04-14 and 2026-04-17 migrations made one bad leaf cascade into "all tabs lost" on the broken stable_02 build. Now we drop only the offending tab and log a `warn!` keyed by its row id, so the rest of the window's tabs still restore. No schema or migration change. Adds three behavioural tests covering: a bad blob between two good ones keeps both good tabs; the warn path runs without panicking; and a window where every blob is bad returns an empty tab list rather than panicking. Fixes warpdotdev#9109
|
I'm starting a first review of this pull request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This PR rewrites the per-tab read_root_node failure path during SQLite restore to log a warning before skipping that tab, and adds corruption fixtures around missing code_panes rows.
Concerns
- The implementation does not change the skip behavior claimed by the PR: the old
.ok()?insidefilter_mapalready returnedNonefor the current tab and continued to later tabs. The new tests assert that existing behavior, so they do not demonstrate or fix an all-tabs-loss regression.
Verdict
Found: 0 critical, 1 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| log::warn!( | ||
| "Skipping tab id={tab_id_for_log} during restore: failed to read pane tree: {err}" | ||
| ); | ||
| return None; |
There was a problem hiding this comment.
.ok()? inside filter_map also returned None for just this tab and continued iteration, so the added behavioral tests would pass before this change. Please add a regression that fails on the old code or fix the actual path that causes all tabs to be lost.
|
@captainsafia @seemeroland, flagging since you both helped land #9503. Would value your call here. @oz-for-oss you're right. I missed that Looking at the wider failure surface, the actual all-tabs-loss path is at Without a reproducer DB I'd be guessing at the exact failing query. Two options:
Leaning toward (1) since (2) feels like salvaging a misframed PR. Happy to do either. What would you prefer? |
Description
read_sqlite_datawas usingfilter_map(read_root_node(...).ok()?)to assemble the saved tabs of a window, which silently dropped every tab whose pane tree failed to deserialize. After the2026-04-14-150000_add_code_pane_tabsand2026-04-17-020439_add_custom_vertical_tabs_title_to_pane_leavesmigrations, a single bad leaf (typically an orphancode_panesrow) would short-circuit the iterator and cause the user to lose every tab in that window — not just the broken one.This PR replaces the silent drop with skip-and-log: a
log::warn!keyed by the offending tab id, and the iterator continues with the remaining tabs.No schema change. No new migration. Read-side fix only — safe to roll back via revert.
The fix prevents future tab loss but cannot recover sessions already overwritten by
save_app_stateon the broken stable_02 build; that data is gone before this code runs.Fixes #9109.
Testing
Added 3 behavioural tests in
app/src/persistence/sqlite_tests.rs:restore_skips_bad_pane_tree_keeps_others— DB with [good, bad, good] tabs returns the two good tabs and emits the warn for the bad one.restore_logs_error_on_bad_blob— the warn-and-skip path runs without panicking.restore_with_all_bad_blobs_returns_empty_not_panic— graceful degradation when every tab is bad: empty list, no panic.Plus three small fixture helpers (
terminal_tab_snapshot,code_tab_snapshot,window_with_tabs) andorphan_all_code_panesto deliberately break pane trees the same way the April migrations did../script/presubmitis clean:cargo fmt,cargo clippy --workspace --all-targets --tests -- -D warnings,clang-format,wgslfmt, and the targetedcargo nextest run -p warp 'persistence::sqlite'all green. The 5shell_integration_tests::*ssh*failures observed locally are unrelated to this change — they require a Docker SSH container — and are skipped on fork PRs per #9304.Manually verified on macOS: dev build (
cargo run) restored an existing 3-tab window cleanly, with noSkipping tab id=warnings (correct behaviour on a healthy DB — that branch only fires on bad blobs).Agent Mode
CHANGELOG-BUG-FIX: Tabs no longer disappear on restart when one pane fails to read from the persistence DB; the bad tab is skipped and logged instead.