Summary
omnideck update aborts before recreating the container if the Stop (or Remove) step returns an error — most notably when the container isn't currently running. The new image is pulled, but the container is never recreated, so the update silently doesn't take effect.
restart, stop, and uninstall already tolerate this error class via isAlreadyStopped; update does not. That inconsistency is the bug.
Root cause
update runs four sequential steps (tui/update.go):
Pull latest image -> Stop container -> Remove container -> Run container
The Stop and Remove steps return the raw engine error:
// tui/update.go
case 1: // Stop container.
workCmd = StepCmd(i, func() (string, error) {
return "", eng.StopContainer(cfg.ContainerName)
})
case 2: // Remove container.
workCmd = StepCmd(i, func() (string, error) {
return "", eng.RemoveContainer(cfg.ContainerName)
})
Any step error becomes a StepFailedMsg, which the model turns into PhaseError and stops — it never advances to step 3 (Run container):
case StepFailedMsg:
...
m.Phase = PhaseError // aborts; Remove/Run never run
Meanwhile the other lifecycle commands explicitly tolerate a stopped/absent container:
// cmd/restart.go (also cmd/stop.go, cmd/uninstall.go)
if err := eng.StopContainer(cfg.ContainerName); err != nil {
if isAlreadyStopped(err) { // "not running" / "No such container"
fmt.Println(... "already stopped")
} else {
return err
}
}
isAlreadyStopped (cmd/uninstall.go) matches "not running", "is not running", "No such container" — exactly the errors docker/podman stop emit for a stopped or missing container. update has no equivalent guard, so it dies on step 1 instead of continuing to recreate.
Repro
omnideck stop (or otherwise leave the container not running).
omnideck update.
- Observe: it pulls the image, then fails at Stop container ("... is not running" / "No such container") and exits at
PhaseError. The container is never removed/recreated, so the freshly pulled image is not applied.
Impact
A user who updates while the container is stopped (or after a crash that left it absent) gets a pulled-but-unapplied image and no clear signal that the update didn't land — they keep running the old image until they manually start/restart/recreate. This is the "I updated but nothing changed" failure mode.
Suggested fix
In tui/update.go, make the Stop and Remove steps tolerant of an already-stopped / missing container (reuse isAlreadyStopped / isNotFound, or move that helper somewhere shared) so the flow always proceeds to Run container. Stop and Remove are setup-for-recreate, not hard preconditions — their "nothing to stop/remove" outcome should be a success, matching restart/stop/uninstall.
Note
Found while investigating a separate report (stale frontend after an image update). That particular case had the container running, so this edge case wasn't the direct cause there — but the asymmetry is a real robustness bug worth closing on its own.
Summary
omnideck updateaborts before recreating the container if the Stop (or Remove) step returns an error — most notably when the container isn't currently running. The new image is pulled, but the container is never recreated, so the update silently doesn't take effect.restart,stop, anduninstallalready tolerate this error class viaisAlreadyStopped;updatedoes not. That inconsistency is the bug.Root cause
updateruns four sequential steps (tui/update.go):The Stop and Remove steps return the raw engine error:
Any step error becomes a
StepFailedMsg, which the model turns intoPhaseErrorand stops — it never advances to step 3 (Run container):Meanwhile the other lifecycle commands explicitly tolerate a stopped/absent container:
isAlreadyStopped(cmd/uninstall.go) matches"not running","is not running","No such container"— exactly the errorsdocker/podman stopemit for a stopped or missing container.updatehas no equivalent guard, so it dies on step 1 instead of continuing to recreate.Repro
omnideck stop(or otherwise leave the container not running).omnideck update.PhaseError. The container is never removed/recreated, so the freshly pulled image is not applied.Impact
A user who updates while the container is stopped (or after a crash that left it absent) gets a pulled-but-unapplied image and no clear signal that the update didn't land — they keep running the old image until they manually
start/restart/recreate. This is the "I updated but nothing changed" failure mode.Suggested fix
In
tui/update.go, make the Stop and Remove steps tolerant of an already-stopped / missing container (reuseisAlreadyStopped/isNotFound, or move that helper somewhere shared) so the flow always proceeds to Run container. Stop and Remove are setup-for-recreate, not hard preconditions — their "nothing to stop/remove" outcome should be a success, matchingrestart/stop/uninstall.Note
Found while investigating a separate report (stale frontend after an image update). That particular case had the container running, so this edge case wasn't the direct cause there — but the asymmetry is a real robustness bug worth closing on its own.