## TL;DR
Find the exception the script swallowed: a run marked FAILED while training appears to complete usually means an error in a finally block, a callback, or the process exit path, or the script's main work finished but a later logging or artifact step threw. Read the run's tags and the full job log after the training-complete line, and check the exit code the wrapper actually returned.

```text
MLflow run ended with status FAILED error but training script completed
```

## Use this when
- The run or call fails with this symptom: MLflow run ended with status FAILED but the training script completed.
- You are working on an MLflow training job whose run status disagrees with its visible result and the failure repeats on the same run or configuration.
- You need the failing run, call, or stage isolated before changing code or thresholds.

## Not for this skill when
- A run failed because the job was genuinely killed, such as an out-of-memory kill, where the fix is resources rather than error handling.
- The error text names a different tool, stage, or root cause. Match the verbatim error first and use that skill.

## Steps
1. Open the job's complete log and read past the training-finished message for tracebacks in cleanup, logging, or upload steps. Verify: the post-training error, if any, is located
2. Check the process exit code recorded by the scheduler or wrapper, separate from the training loop's own success print. Verify: the real exit code is known
3. Look for broad exception handlers that mark the run failed on any error, including ones raised after the model was saved. Verify: the status-setting code path is identified
4. Fix the failing late step or scope the failure marking to training errors, then rerun and confirm the status. Verify: the run ends FINISHED with artifacts present

## Variant phrasings
### mlflow run failed status but training completed
The verbatim phrasing.
### mlflow run marked failed after successful training
The status-mismatch phrasing.
### mlflow fluent run ends failed exit code wrapper
The wrapper phrasing.

Compatibility: MLflow 2.x and 3.x run lifecycle in training scripts

## Why it happens
Run status is set by the tracking calls and the process outcome, not by whether the model trained. Errors after the main work, in artifact upload, metric flushing, or exit handlers, flip the status while the visible training output still looks like a clean success.

## Edge cases / pitfalls
- A run left in RUNNING by a killed process is a different symptom; this skill covers runs that reach FAILED.
- Nested runs can fail on a child while the parent finishes; check which run in the tree holds the FAILED status.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_cDtb4NrKvEWtrH3EzQBhpA
