Skip to content

st2 up --once exits 0 when the reconcile pass was skipped #4

Description

@schickling-assistant

st2 up --once exits 0 when the reconcile pass was skipped, so exit status is not evidence that a reconcile happened.

Verified at 4e25f56. Apologies if this is already addressed in work you have locally.

Mechanism

When pty list --json fails, the pass returns early with the error recorded in the report:

  • src/run.rs:645 and src/run.rs:803report.errors.push(format!("list sessions (pass skipped): {e}")); return report;

--once prints the report and returns Ok(()) regardless:

  • src/main.rs:1691-1696 (catalog path) and src/main.rs:1588-1595 (st2 up <spec> --once)

So "no pass happened" and "a pass happened and everything is fine" are the same exit status. print_report writes the errors to stderr, but stderr is not what a supervisor, systemd ExecStartPre, or a CI step checks.

Reproduction

At 4e25f56, with a failing pty placed first on PATH for that one invocation only:

cat > "$SHIM/pty" <<'SH'
#!/bin/sh
echo "pty: simulated failure" >&2
exit 1
SH
chmod +x "$SHIM/pty"

( PATH="$SHIM:$PATH" st2 up --catalog "$CATALOG" --host <host> --once; echo "EXIT=$?" )
reconcile pass on host '<host>':
error: list sessions (pass skipped): `pty list --json` failed: pty: simulated failure

EXIT=0

Nothing was launched. Exit 0.

Impact for an adopter

st2 up --once is the natural building block for a one-shot boot step — a deploy hook, a unit ExecStart, a health gate. We use it exactly that way. A transient pty failure makes it a silent no-op that reports success, and the fleet stays down while the orchestration layer records a clean run. The distinction that matters is not "were there errors" (an individual agent can legitimately fail while the pass still ran) but "did a reconcile happen at all".

Offer

We have a PR with a regression test: an explicit skipped flag on UpReport, set at the two early returns, with --once exiting non-zero when it is set. That keeps "a pass ran and had per-agent errors" distinct from "no pass ran", and leaves the supervising loop's behaviour untouched. Happy for you to reshape or reject it — the same flag would also let the loop escalate a persistently skipping pass, but we did not presume to change loop semantics.

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

    area:reconcileSupervisor run loop, lifecycle, restart, park, and teardown · Set: manualorigin:agentFiled or primarily produced by an AI agent · Set: manualtype:bugSomething broken or a regression · Set: manual

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions