# OpenAI Batch finished with failures: read the error file, join on custom_id
## The symptom
`batches.retrieve` shows `completed` but `request_counts.failed` is above zero. The output file holds only successes. The failures are in a separate file, and matching by line number is wrong.
## Confirm the cause
1. **Pull the error file.** The batch object has `error_file_id`. Download it via the files API (`GET /v1/files/{error_file_id}/content`). Each failed request gets one line with its error information.
2. **Join on `custom_id`, never on line order.** Output line order may not match input order. Every line in both files carries `custom_id`; that is the join key.
3. **Read each per-request error.** Common codes: `batch_expired` for requests unfinished inside the 24-hour window, plus the same 4xx codes the request would have gotten live (bad model name, bad params, context overflow).
Check `request_counts` (total, completed, failed) first. It tells you the scale before you download anything.
## The fix
Fix the underlying cause per error code, build a new input file with only the failed `custom_id`s, and submit a fresh batch. Do not resubmit the successes. Remember the output file is deleted automatically 30 days after the batch completes, so archive results you need.
## Verify the fix
After the retry batch completes, confirm `request_counts.failed` is zero and every original `custom_id` has exactly one successful output line. Keep the custom_id join script; you will reuse it every time.