Recover from an interrupted job or damaged state
Recover a deployment rotation while the Console is stopped
For an installer-owned Docker, split Docker or Kubernetes deployment, connect to the installer host over SSH. Use the same private state directory as the maintenance worker:
sudo irisctl maintenance --state-dir /var/lib/iris-installer/iris status
Find the backup, rotation or restore marked recovery-required. Check its operation ID,
backup or key type, and recorded results. Resume that operation:
sudo irisctl maintenance --state-dir /var/lib/iris-installer/iris recover \
--job-id <operation-id> --allow-downtime
Confirm when asked, then run status again to check completion. The worker uses
the saved operation record. An accepted request is not proof of completion.
For an interrupted backup, recovery restarts the original services and checks
whether both archives completed. It keeps incomplete output and never starts
another capture. Review the result before requesting a new backup.
If the attempt stopped before service changes began, recovery closes it as
failed without restarting services. Missing or changed recovery records require
inspection; keep the original records and files in place.
The installer manages the worker as a host service outside the containers or pods.
If it is unavailable, check irisctl worker-status and use
irisctl worker-service --action restart with sudo. Pass the same --state-dir to both.
Reconnect recorded backup storage before restarting a worker that reports
missing or changed storage.
Warning
Preserve the operation journal and encrypted backup. Recovery refuses changed authority; do not delete the journal or reset keys to bypass that refusal. Restore requires the same owned deployment, matching credentials and current instruction counters and revocations. A lost host or missing current security records requires separate review before service startup.
Restore recovery resumes the recorded replacements and verifies server health and authenticated Console access. A failed restart may have written newer state; the worker preserves it when resuming. Use the same operation ID and retain its original data directories. For a new restore, follow Restore a backup.
For local k3s installations, backup, credential rotation, and restore protect the recorded server and Console images from automatic image cleanup before stopping services. If an image is missing, restore recovers its exact bytes from the authenticated backup.
Replace the independent recovery recipient
Create the replacement with iris-key-setup. Keep an independent private copy off the deployment host. Put a protected copy of this recovery key on the installer host, outside deployment and backup folders. Then run:
sudo irisctl maintenance --state-dir /var/lib/iris-installer/iris replace-recovery \
--identity /protected/path/recovery.age --independent-copy --allow-downtime
Compare the public recipient with your independent copy and confirm when asked.
The worker checks the matching host-prepared key before backup or downtime and
checks it again before changing encrypted data.
Use status to check the operation. This private recovery key stays outside the
Console. Private signing roots must remain on their holders' machines.
Finish an active rotation before preparing another recipient. Existing backups still require their original recovery keys. Retain those keys and your independent copies after the new recipient is active.
What this is for
A job that stops partway through, or storage that comes back with the wrong file permissions, leaves IRIS stuck. Each procedure here clears one state.
What you see
| Symptom | Likely cause | What to do |
|---|---|---|
Every job on one IOx device ends in error with the category reconciliation_required |
An attempt was cut off while device-wide app signature verification was turned off | Recovering an IOx attempt cut off mid-run |
An IOS-XR undeploy stopped partway and the device shows a red needs-reconcile badge |
The job ended before teardown finished | Recovering an interrupted IOS-XR teardown |
A Guest Shell job reports copy_failed, and a later job says the hash launch was never confirmed |
The native hash job's result was lost | Recover an interrupted Guest Shell root-hash job |
| The server refuses to start and reports an unsafe deployment-authority or transcript mode | A volume mount rewrote private file modes | Repair a volume whose file permissions were changed |
| A read of a device store fails, and the file at its old path is not valid JSON | A reader used the retired whole-fleet path | Inspect retained per-device migration evidence |
Recovering an IOx attempt cut off mid-run
This covers Industrial Ethernet switches with app hosting, Catalyst 8000
series routers, and Catalyst 9000 series switches with app-hosting storage,
where the IOx app replaces the Guest Shell agent. A cut-off onboard or undeploy leaves
the device's IOx verification journal in phase indeterminate. Every later job
on that device, Force included, then ends in error with result code 3 and the
category reconciliation_required. Its job log starts with
IOx controller: predecessor recovery failed and names the values to
reconcile.
-
Read the binding. Take the record id, transaction id and revision from that job-log line, or from
record.iox_verificationinGET /api/v1/devices/<id>/deployment. Use the journal's current revision; an older number is refused as stale. -
Restore verification on the device. In privileged EXEC:
show app-hosting infra | include App signature verification
app-hosting verification enable
show app-hosting infra | include App signature verification
The second read must report App signature verification: enabled.
Verification is device-wide, so check the other IOx applications on the
device first. See
Prepare Industrial Ethernet switches with app hosting, Catalyst 9000 and 8000 devices for the IOx app.
- Reconcile the journal from inside the server container, as the service user:
docker compose -f server/docker-compose.yml exec -w /opt/iris/server iris \
python3 iox_verification.py reconcile-enabled \
--record-id <record-id> --transaction-id <transaction-id> \
--revision <revision> --acknowledge-external-resolution \
--wait --wait-timeout 600
It reads the device once over SSH and closes the journal when the device
reports enabled. See Helper commands.
- Clear what the attempt left behind. Run Undeploy with Force in
the Console, or
POST /api/v1/devices/<id>/undeploywith{"force": true}. Then onboard the device again.
What the exit status means
| Exit status | Meaning | What to do |
|---|---|---|
0 |
Resolved. | Go on to step 4. |
3 |
The job log says fresh read did not establish enabled. |
Go back to step 2. |
2 with {"error": "request rejected"} |
The binding is stale or mistyped. | Read the binding again. |
4 |
A wait timeout or a transport failure. | Read the job with job --job-id <id> --wait before retrying. |
5 |
A journal or authority fault. | Read the server log. |
Job error categories
A job ends with the category reconciliation_required when the journal is
indeterminate, or when two unresolved journals claim one device. For HTTP
errors, see API error codes (problem types).
Recovering an interrupted IOS-XR teardown
This covers Cisco 8000 series routers on IOS-XR, validated on a Cisco 8201.
NCS-540 registration and app startup are validated; undeploy is not yet
validated on NCS-540. An interrupted undeploy leaves the deployment record in
needs-reconcile, a red badge in the Console. Run
undeploy again from that state, record-backed or with Force: each step
re-probes the router, including the appmgr application, before acting.
IRIS_XR_SESSION_TIMEOUT bounds every command session to the router, so a
wedged router fails the job with a real exit code; 0 turns the bound off. See
Server configuration for the default.
A finished teardown may leave an empty iris-work/ directory on harddisk:,
which a later onboarding reuses.
Undeploy, retire and clean up devices lists what it removes.
Recover an interrupted Guest Shell root-hash job
This covers Catalyst 9000 series switches, where the agent runs in Guest Shell;
the IOx app is the alternative on switches with app-hosting storage. When an
image of the same name already sits in the IOS root file system, the agent
hashes it in place with a native Embedded Event Manager (EEM) policy,
IRIS-ROOT-HASH. A lost result reports copy_failed and asks you to look at
the device.
- Remove the
IRIS-ROOT-HASHapplet from the running configuration. - Wait at least 625 seconds for any job already started to finish.
- Inspect the EEM job history.
- Remove only
<stage_dir>/.iris-root-hash.json. The next check-in retries.
Warning
While the agent is running, leave <stage_dir>/.iris-root-hash.lock, the
staged image, the IOS root image and any BOOT target in place.
Repair a volume whose file permissions were changed
A storage driver that rewrites permissions on mount widens the private files holding the deployment authority and the IOx transcripts, and the server refuses to start. Install on Kubernetes has the mount settings that prevent this. Keep the failure evidence, then repair the storage:
- Stop new job admission, wait for all onboard, undeploy and scheduled work to finish, then stop the server pod and any maintenance pods on the volume.
- Inspect ownership, modes, inode and link metadata against trusted backup evidence, without printing file contents. A change to content or identity needs investigation instead.
- Restore only the verified, explicitly identified paths, each owned by
10001:10001:
| Path | Mode |
|---|---|
/data/state/deployment_records.json, its .lock, IOx transcript files |
0600 |
/data/state, /data/state/iox, its authority subdirectories |
0700, setgid cleared |
/data/config/tls/crt.pem, the public catalog certificate |
0644 |
Startup rejects group-writable modes such as 0660 or 0664. Check other
authority files and instruction roots against their own rules.
4. Verify the volume root is 10001:10001 with mode 2770, apply the
OnRootMismatch policy to the Deployment, then start the server.
5. Recheck the private modes, then verify management API health and
deployment-record access before you admit jobs.
Warning
Never use recursive chmod or chown, never delete authority evidence,
never weaken the validators, and never change permissions while a job runs.
Inspect retained per-device migration evidence
The server now keeps one file per device instead of one whole-fleet JSON
document per store. See
Data formats and states. The original
document keeps a .migrated suffix. An invalid placeholder at its old path
names the retained document and current data directory. Keep both as evidence.
- Stop every reader and writer of the selected store.
- Back up the whole state volume: per-device files, revision metadata,
placeholders, and
.migratedfiles. - Check the original deployment's recorded source and state paths. Its per-device readers use the current files, not the retired whole-fleet path. For same-deployment recovery, follow Restore a backup with current security records and a consistent backup.
- Verify inventory and policy together. An empty store is not a successful recovery.
Warning
Do not replace the placeholder with the retained document or run older application code against this store. The retained document can omit newer writes. Keep the per-device files, guard and backup intact.
For another release, follow Deploy a new release: remove the old deployment, install its replacement and onboard devices to the new identity.
Replace the two root keys
Replacing the two offline keys that sign every instruction key, and recovering a lost one, are on Replace or recover signing keys.
A server restart also marks any deployment record for a job that was still
running as unknown, not active or failed. Do not retry the device
operation blindly: read the record first and reconcile from it, the same way
as for a cut-off IOx attempt above.
With the API
GET /api/v1/devices/<id>/deployment returns the deployment record, with
record.iox_verification and the iox_verification_obligations summary.
POST /api/v1/devices/<id>/undeploy runs a teardown; send {"force": true}
for Force. Both are described in Console API.
Certificate renewal and backup jobs
| Result | Next step |
|---|---|
| Online key or certificate changed | Prepare a new request in Settings → Certificates & keys, then obtain approval for the current key. |
| Renewed certificate must extend the existing expiry | Check the file returned by the key holder; an older approval cannot replace a newer certificate. |
| Lifecycle worker unavailable | Check the worker on the installer host and its dedicated control mount. See Back up and restore. |
| Backup refused for storage sharing, space or an unclean stop | Correct the reported host condition before retrying. Check that the original services recovered. |
recovery-required |
Use the recovery action beside the original operation in the Console, or the host recovery command if it is offline. If recovery refuses changed or missing records, keep the private state and unfinished files for inspection. |
| Backup signature rejected | Compare the signer with the independently recorded public key. Do not replace trusted signer material with a key supplied beside an unverified archive. |
verified-isolated-files |
File extraction passed. Keep the target isolated until former-primary fencing, instruction history and revocations have been reconciled. |