# Run problems

Why a run refused to start, paused and stayed paused, halted early, or did nothing at all. Symptom first, then what to change.

Source: https://opafra.com/docs/troubleshooting/runs

---

Problems after the connection works. Find the symptom.

## The run will not start

**"Already has a run in progress on the same targets"** means the concurrency guard
stopped it. The same plan is already running against at least one of the same hosts, and
the overlapping hosts are named in the message.

Wait for the first run, or enable concurrent runs on the plan if overlapping runs are
genuinely safe. Usually they are not, which is why the guard defaults on.

## It paused immediately and stayed paused

The run targets an environment that requires approval, so it is waiting for a person. Its
status is **Paused** and it is in the approvals inbox.

Two things people expect to help and do not: restarting the run creates a second waiting
run, and waiting longer changes nothing. It needs an approver with Operator or above.

> **Note**
>
> This catches scheduled runs most often. A gated plan scheduled for 02:00 is waiting at
> 02:00, not running. See [scheduling](/docs/running/scheduling).

If nobody can approve it, check whether the approver has Operator or above and whether the
environment is also **protected**, which additionally requires an explicit grant.

## A step failed and everything after it was skipped

That is the intended behaviour. A run halts at the first failed step in every mode,
because the rest of a plan usually assumes the earlier steps worked.

Read the failed step's output for the host it failed on. Then either fix the cause and
re-run, or declare the failure tolerable in the plan with `continue_on_error`. See
[plan structure](/docs/plans/structure).

## It worked on some hosts and not others

Normal and informative. Steps run per host, and hosts differ.

The usual causes, in the order worth checking: the package or path exists on some hosts
and not others; `sudo` works for the account on some and not others; or a variable
resolved differently because the hosts are in different environments.

A [dry run](/docs/running/dry-run) shows exactly this before the change rather than during
it, which is why it is worth running when the target list grows.

## A command did nothing, or acted on the wrong path

Almost always an unresolved variable. A `{{ vars.x }}` that resolves to nothing becomes an
empty string, which turns `/srv/{{ vars.app }}` into `/srv/` and a service name into
nothing at all.

Dry run it and read the unresolved-variables list at the bottom of the report. That is
exactly what it is for.

Check also which namespace you meant: `{{ vars.x }}` is the merged value, `{{ env.x }}` is
this host's environment only, and `{{ inputs.x }}` is run overrides only.

## A step ran that should not have

Check its condition. A **malformed condition fails open**, so the step runs and a warning
is logged.

This is deliberate: a broken guard that silently skipped steps would mean production
automation quietly stops happening and nobody notices. But it does mean a condition with a
typo is not a guard. Verify it in a dry run, where a step that should be skipped shows as
running.

## The same line keeps getting added to a file

A raw command doing `echo >> file` appends every time the plan runs. It is not idempotent
and nothing can make it so.

Use `file.lineinfile`, which will not duplicate a line it already wrote. See
[commands and scripts](/docs/plans/commands-and-scripts).

## A run is stuck at Running

If Opafra restarted mid-run, a run can be left marked as running with nothing executing.
Aborting it settles the record.

A genuinely long run is different: check the step it is on and whether that command would
finish unattended. A command waiting on input never will, and `sudo` prompting for a
password is the most common version of that.

## Sudo worked in my terminal but not in the run

Your interactive session can answer a password prompt. A run cannot.

The connection check reports this as a warning under the sudo stage. Grant passwordless
sudo for the account, scoped to the commands the host is actually managed with.

## A secret came through empty

Check the reference resolves: the provider is connected, the namespace and key are right,
and the reference sits inside your own tenant's namespace. A reference pointing outside it
is rejected rather than followed.

Note that a redacted value in a preview is **not** an empty one. `secret://[redacted]` in
a dry run means the reference is present and hidden, which is correct.

## The dry run said no change but the real run changed something

Possible and expected in one case: a preview is taken against the host as it is *now*, not
as an earlier step in the same plan would have left it. Where step 2 creates a file and
step 3 edits it, step 3's preview is taken before step 2 ran.

If nothing in the plan explains it, something changed on the host between the preview and
the run.

## Next steps

- [Running a plan](/docs/running/executing) for modes, statuses and failure behaviour
- [Connection problems](/docs/troubleshooting/connections) for failures before a run starts
