Summary
scripts/continuum_save.sh:fetch_and_run_tmux_resurrect_save_script calls set_last_save_timestamp unconditionally after exec-ing the save script. When the configured save script silently fails (wrong path, missing file, non-zero exit, any error swallowed by >/dev/null 2>&1), the last-save timestamp still advances every interval. Result: @continuum-save-last-timestamp reports healthy saves indefinitely while nothing is being written to disk.
I debugged this in my own setup after losing window layout on a reboot. find ~ -name 'tmux_resurrect_*' -type f returned zero files despite @continuum-save-last-timestamp showing a fresh value updated 15 minutes earlier. The "save" had been failing silently for an unknown duration — possibly weeks.
Current code (master @ 0698e8f)
fetch_and_run_tmux_resurrect_save_script() {
local resurrect_save_script_path="$(get_tmux_option "$resurrect_save_path_option" "")"
if [ -n "$resurrect_save_script_path" ]; then
"$resurrect_save_script_path" "quiet" >/dev/null 2>&1 & # backgrounded
set_last_save_timestamp # ← always called
fi
}
Two issues compound:
& backgrounds the save — the caller never sees the exit code
set_last_save_timestamp runs immediately after, regardless of what the save script does
Reproduction
Targeted reproduction at the function level (works without spinning up a full tmux server). Source the function with stubbed dependencies, point @resurrect-save-script-path at probes with different exit codes:
| Case |
Behaviour |
Expected |
| probe exits 0 |
timestamp advances |
advances ✓ |
| probe exits 1 |
timestamp advances |
should NOT advance |
@resurrect-save-script-path points at a missing file |
timestamp advances |
should NOT advance |
@resurrect-save-script-path unset |
no-op (no timestamp) |
no-op ✓ |
The 2nd and 3rd rows are the bug. Verified both before and after applying the proposed fix below.
Related issues / PRs
Proposed fix (PR forthcoming)
Two changes, ~3 lines of diff:
fetch_and_run_tmux_resurrect_save_script() {
local resurrect_save_script_path="$(get_tmux_option "$resurrect_save_path_option" "")"
if [ -n "$resurrect_save_script_path" ]; then
if "$resurrect_save_script_path" "quiet" >/dev/null 2>&1; then
set_last_save_timestamp
fi
fi
}
- Drop
& — run the save synchronously so the caller sees the exit code
- Gate
set_last_save_timestamp on success — failure leaves the timestamp put and the next tick retries
Behavioural cost: one save-script duration is added to one status refresh per save-interval (default 15 min). Tested locally with pane-contents capture across 10 panes: ~80ms. Invisible at that scale.
Side benefit: the existing acquire_lock trap now correctly holds the lock for the duration of the save. Previously the trap fired on wrapper exit while the backgrounded save was still running, making the lock effectively a no-op for save serialization.
Workaround for users hitting this now (until/unless this lands)
Until a fix lands, I've shipped a wrapper script and a status-bar widget at https://github.com/pleasedodisturb/terminal-craft — the wrapper provides state-aware skip logic and a real-mtime status widget that reads ground truth instead of @continuum-save-last-timestamp. PR #43 there has the full setup if anyone wants to cherry-pick. Files of interest: scripts/continuum-save-guard.sh, scripts/save-status.sh.
Environment
- tmux 3.6a (Homebrew, macOS arm64)
- tmux-continuum @ master 0698e8f
- tmux-resurrect @ latest master
- bash 3.2.57 (system bash on macOS)
Summary
scripts/continuum_save.sh:fetch_and_run_tmux_resurrect_save_scriptcallsset_last_save_timestampunconditionally after exec-ing the save script. When the configured save script silently fails (wrong path, missing file, non-zero exit, any error swallowed by>/dev/null 2>&1), the last-save timestamp still advances every interval. Result:@continuum-save-last-timestampreports healthy saves indefinitely while nothing is being written to disk.I debugged this in my own setup after losing window layout on a reboot.
find ~ -name 'tmux_resurrect_*' -type freturned zero files despite@continuum-save-last-timestampshowing a fresh value updated 15 minutes earlier. The "save" had been failing silently for an unknown duration — possibly weeks.Current code (master @ 0698e8f)
Two issues compound:
&backgrounds the save — the caller never sees the exit codeset_last_save_timestampruns immediately after, regardless of what the save script doesReproduction
Targeted reproduction at the function level (works without spinning up a full tmux server). Source the function with stubbed dependencies, point
@resurrect-save-script-pathat probes with different exit codes:@resurrect-save-script-pathpoints at a missing file@resurrect-save-script-pathunsetThe 2nd and 3rd rows are the bug. Verified both before and after applying the proposed fix below.
Related issues / PRs
lastsymlink. Different surface, same architectural root (assumptions about backgrounded operations succeeding). Independent fix; both can land.Proposed fix (PR forthcoming)
Two changes, ~3 lines of diff:
&— run the save synchronously so the caller sees the exit codeset_last_save_timestampon success — failure leaves the timestamp put and the next tick retriesBehavioural cost: one save-script duration is added to one status refresh per save-interval (default 15 min). Tested locally with pane-contents capture across 10 panes: ~80ms. Invisible at that scale.
Side benefit: the existing
acquire_locktrap now correctly holds the lock for the duration of the save. Previously the trap fired on wrapper exit while the backgrounded save was still running, making the lock effectively a no-op for save serialization.Workaround for users hitting this now (until/unless this lands)
Until a fix lands, I've shipped a wrapper script and a status-bar widget at https://github.com/pleasedodisturb/terminal-craft — the wrapper provides state-aware skip logic and a real-mtime status widget that reads ground truth instead of
@continuum-save-last-timestamp. PR #43 there has the full setup if anyone wants to cherry-pick. Files of interest:scripts/continuum-save-guard.sh,scripts/save-status.sh.Environment