When a background task fails, the task log captures the output, but you still need a systematic process to figure out the cause and decide whether to retry, fix and retry, or accept the failure.
Systematic Debugging
- Read the error message. It almost always points at the root cause directly.
- Look at the input parameters. Was it a bad input? Missing required field? Stale cached value?
- Check related logs. Activity log, email log, API log — the task may have failed because something upstream failed.
- Re-run on a single record. Use the “run on input” button to test against just the offending record.
- Reproduce in dev. Pull the same input and run locally with full debugger.
- Apply fix. Either code change, config change, or data clean-up.
- Retry the failed batch. Or mark resolved if the underlying issue went away on its own.
Common Failure Modes
- Timeouts: Long-running task hit the PHP max_execution_time. Solution: chunk the work or raise the limit.
- Memory limits: Big imports OOM'd. Stream rows instead of loading into an array.
- External service errors: Stripe/SendGrid/Slack returned 503. Solution: built-in retry with exponential backoff usually handles this — check it triggered.
- Locked rows: Two tasks tried to update the same row. Reduce concurrency or use row-level locking with a sensible timeout.
- Schema drift: Task references a column that was renamed. Update the task code.
Worked Examples
- Email send failed for one user: Log shows “invalid recipient address”. Look at the user's email field — it had a trailing space. Clean up, retry.
- Nightly export timed out: 200,000 rows now instead of 50,000. Chunk into 4 batches; reschedule.
- External API down: Multiple tasks failed with 5xx from Stripe. After Stripe recovers, replay all queued failures.
- Memory exhausted: Convert
foreach ($all_rows as $row)to a cursor pattern. Re-run the task.