Skip to content

omnideck update aborts before recreating the container when it isn't running (stop-step error not tolerated like restart/stop) #6

Description

@lefoulkrod

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

  1. omnideck stop (or otherwise leave the container not running).
  2. omnideck update.
  3. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions