Skip to content

bug(deploy): the provisioning failure summary counts ignored tasks as failures and failure events as hosts — "3 hosts failed" on a 2-host run #17240

Description

@mrveiss

A provisioning run reported "3 hosts failed" on a two-host deployment, naming the same
host three times. Two of the three reported failures were tasks that ansible had already
ignored by design. Both defects are in _extract_failure_summary
(autobot-slm-backend/services/ansible_utils.py:103-150).

Defect 1 — ignored failures are counted as failures

A task with ignore_errors: true still prints a full fatal: [host]: FAILED! => {...} line,
followed by ...ignoring. The parser keys only on the fatal: prefix
(ansible_utils.py:129) and never looks for ...ignoring, so a task that succeeded by
design is reported as a failure.

This is not hypothetical — it is the designed first-run path. Both marker reads in
autobot-slm-backend/ansible/roles/_shared/tasks/sync_deletions.yml carry
ignore_errors: true (:105 and :112) precisely because a host with nothing deployed yet
has no marker to read:

  • .autobot_sync_deletions_commit — this module's own marker (:100-105)
  • .deployed_commit — the legacy read-only bootstrap, itself guarded by
    when: _sd_own_marker is failed (:107-113)

So a first provision always emits two ignored fatal: lines, and the summary always
reports them as failures. The operator is told the deploy failed in two places it was
designed to pass, and the one real failure is buried among them.

Defect 2 — the count is of failure events, labelled as hosts

ansible_utils.py:148-150:

count = len(failures)
noun = "host" if count == 1 else "hosts"
return f"{count} {noun} failed — " + "; ".join(failures)

failures holds one entry per fatal: line, not per host. One host failing three tasks
reports "3 hosts failed". On a two-host deployment that is not just wrong, it is
unreachable — it names more hosts than exist, which is what made the report obviously
suspect.

The existing test cannot catch this. ansible_utils_test.py:79-97
(test_multiple_failures) uses two hosts with exactly one failure each, so failure count and
host count coincide and the conflated variable reads correct. The test encodes the ambiguity
instead of discriminating it.

Why this matters beyond cosmetics

The summary is the operator-facing explanation of a failed provision — the thing #14298 built
so users see a task and a reason instead of exit code 2. When it reports expected-and-ignored
tasks as failures, it inverts that: the noise is indistinguishable from the signal, and the
real failure has to be found by hand in the raw log. That is the same nothing found vs
did not look collapse MEASUREMENT_DISCIPLINE.md exists to prevent, on the output side.

Acceptance criteria

  • A fatal: line that ansible followed with ...ignoring is not reported as a failure.
  • The headline distinguishes failure count from host count; N failures on one host never
    reads as N hosts. A count of hosts never exceeds the number of hosts in the run.
  • A test covers one host with multiple failures (the case the current suite structurally
    cannot fail on), and a test covers an ignored failure being excluded.
  • A run whose only fatal: lines were ignored yields no failure summary, so it cannot
    present a successful deploy as a failed one.
  • The scan for ...ignoring is bounded and cannot mistake a later task's ignored failure
    for this one's.

Related

Activity

  1. added this to the v0.9.0 milestone on Sep 22, 2026
  2. mrveiss commented on Sep 22, 2026

    @mrveiss
    OwnerAuthor

    Branch verdict — new branch issue-17240-failure-summary, off current main (f7ac84a90f)

    Checked before branching: no open PR touches services/ansible_utils.py or its test, so there is nothing to append to; no existing branch carries this change; the file is not a hub file and collides with nothing in flight. Single file plus its test.

    Citations in the issue verified with verify-citations and read individually with numbered output — ansible_utils.py:129 is the fatal: check, :148-150 the count, sync_deletions.yml:105 and :112 the two ignore_errors: true lines.

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions