---
description: Tell a science verdict from a fault by reading the attempt count, find the reason, and bring recoverable materials back with matmelt retry.
---

# Diagnose a failed material

Materials reach `FAILED` for two very different reasons, and the fix differs
completely. This page is how you tell them apart in about ten seconds.

## Start with `status`

```console
$ matmelt status
```

```text
Status of run nacl-demo:
  Materials by state
┏━━━━━━━━━━━━┳━━━━━━━┓
┃ State      ┃ Count ┃
┡━━━━━━━━━━━━╇━━━━━━━┩
│ EXPANDED   │     2 │
│ FAILED     │     3 │
│ STRUCTURED │    32 │
└────────────┴───────┘
                                Failed materials
┏━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Material    ┃ Stage  ┃ Attempts ┃ Reason                                     ┃
┡━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ Cl1Na1_3D-1 │ screen │        3 │ stage 'screen' cannot run on item          │
│             │        │          │ 'Cl1Na1_3D-1': missing or empty required   │
│             │        │          │ input file(s) ['structure.cif'] in         │
│             │        │          │ materials-work/Cl1Na1_3D-1 (one candidate  │
│             │        │          │ crystal from the structure stage)          │
└─────────────┴────────┴──────────┴────────────────────────────────────────────┘
```

`status` exits `0` while listing failures. Failures are content, not a command
failure.

## Read the attempt count first

**`Attempts: 3`** (or whatever your `retry_budget` is) means a **fault**:
something went wrong that might not have. MatMelt retried it to exhaustion. The
cause is almost always environmental — a missing file, a crashed job, a backend
that went away — and it is usually yours to fix.

**`Attempts: 1`** means a **science verdict**: a deterministic rejection.
Nothing was retried, because re-running reproduces it exactly. The material was
screened out on its merits:

```text
material Cl1Na1_3D-3 failed terminally at stage 'screen' (verdict): screened
out: energy -578480.6344 eV/atom outside the physical window [-35.0, 10.0]
eV/atom -- the model is almost certainly extrapolating; minimum interatomic
distance 0.8069 A < 1.2 A -- atoms are overlapping (unphysical geometry);
residual stress 627297760.068 GPa > 2.0 GPa -- unit cell not mechanically
equilibrated; final fmax 293121.41212 eV/A > acceptance gate 0.5 eV/A -- no
local minimum reached
```

Every clause is quantified against a stated bound, so you can judge the
rejection rather than trust it. A verdict like this needs no action: it is the
funnel doing its job. Retrying it only burns the same compute for the same
answer.

The run itself exits `0` either way. A run in which materials were screened out
did what you asked.

## Then read the reason

The reason is stored verbatim, so it names the stage, the material, the file and
the directory. Two shapes come up constantly:

**A contract refusal** — the stage checked its inputs and would not start:

```text
stage 'screen' cannot run on item 'Cl1Na1_3D-1': missing or empty required
input file(s) ['structure.cif'] in materials-work/Cl1Na1_3D-1
```

Note *empty* counts as missing: a truncated file fails the same way a deleted
one does.

**A semantic refusal** — the inputs exist but say the wrong thing, e.g. `extract`
asked to work on a material the screening stage rejected. Both are faults, both
spend the budget, and both are fixed upstream rather than by retrying harder.

To list just the failures as ids — the picking list for a targeted re-run:

```console
$ matmelt status --state FAILED
```

## Fix, then retry

`retry` resets `FAILED` materials so a later run picks them up again. Preview
first; it changes nothing without `--yes`:

```console
$ matmelt retry --dry-run
```

```text
Run nacl-demo: 2 FAILED material(s) across 1 stage(s) to retry:
                           Failed materials by stage
┏━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Stage  ┃ Count ┃ Distinct reasons ┃ Example reason                           ┃
┡━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ screen │     2 │                2 │ stage 'screen' cannot run on item        │
│        │       │                  │ 'Cl1Na1_3D-6': missing or empty required │
│        │       │                  │ in...                                    │
└────────┴───────┴──────────────────┴──────────────────────────────────────────┘
retry --dry-run: nothing changed.
```

Narrow it with `--stage` (everything that failed at one stage) or `--materials`
(a specific list), then apply:

```console
$ matmelt retry --materials Cl1Na1_3D-6,Cl1Na1_3D-10 --yes
```

```text
Reset 2 material(s) -- they will re-run at their failed stage on the next
'matmelt run'.
```

Each material resumes from **its own** timeline — the output state of the last
stage it actually completed — so a reset is correct even if you have since
changed the funnel. The completion history is preserved, and the lease, attempt
count and error are cleared.

Then run again. In this capture the underlying cause (two `structure.cif` files
truncated to zero bytes) had been fixed first, so the materials went straight
through:

```console
$ matmelt run --only screen --materials Cl1Na1_3D-6,Cl1Na1_3D-10 --yes
```

```text
pass 23: completed=1
pass 33: completed=1
  Materials by state
┏━━━━━━━━━━━━┳━━━━━━━┓
┃ State      ┃ Count ┃
┡━━━━━━━━━━━━╇━━━━━━━┩
│ EXPANDED   │     2 │
│ FAILED     │     3 │
│ SCREENED   │     2 │
│ STRUCTURED │    32 │
└────────────┴───────┘
```

**Retrying without fixing the cause reproduces the failure**, one budget at a
time. `retry` re-queues; it does not repair.

## When a run refuses to start at all

A missing dependency is caught before any material is touched:

```console
$ matmelt run --yes
```

```text
Run nacl-demo: compose -> structure
Seed enumeration: 2 element(s) -> 1 combination(s) (size 2: 1).
run: not ready -- missing requirements:
  compose: smact (ModuleNotFoundError: No module named 'smact')
To fix, run:
  /usr/bin/python3 -m pip install smact
```

Exit `1`, nothing queued, nothing failed. The preflight covers only the stages
this run would actually execute, so a missing `calculate` dependency cannot
block a run that stops at `screen`. See {doc}`doctor`.

## Related

- {doc}`../reference/states` — what each state means and which are terminal.
- {doc}`stop-and-resume` — pausing and continuing without losing work.
- {doc}`../tutorials/t5-start-mid-funnel` — the same refusals worked through as
  a tutorial.
