Runs and failure reasons
Every time Delay sends a request, it records a run: what was sent, what came back, how long it took and, if it failed, why. Crons call their runs executions. Each job attempt has exactly one run, and every retry is a new job with its own run.
Where to find runs
- Crons: open the cron from Cron jobs. Recent executions shows the last 10 runs. View all opens the Execution history, 20 runs per page. Click a row to see its details.
- Jobs: the Jobs list shows each job’s status, HTTP code, failure reason and duration. Open a job to see its request and response.
For a step-by-step walkthrough, see Debug a failed run.
What a run records
| Field | What it holds |
|---|---|
| Started at | When Delay began the run |
| Completed at (crons), Executed at (jobs) | When the response arrived or the run failed |
| Duration | Milliseconds from the start of the run to the response, including the DNS lookup and connecting |
| Response status | The HTTP status code, if a response arrived |
| Response headers | The headers your endpoint returned |
| Response body | What your endpoint returned, up to 65,535 bytes |
| Request headers | The headers you configured |
| Request body | For crons, the payload string as you wrote it. For jobs, the JSON payload. |
| Error message | What went wrong, for example HTTP 503 error or Assertion failed: ... |
| Failure reason | One of the values in Failure reasons |
A few details worth knowing:
- Long bodies are cut. Bodies over 65,535 bytes are stored cut short with
...at the end. The Execution history page shows the first 2,000 characters of each body. Assertions always check the full body, not the stored copy. - Delay’s own headers aren’t listed. Request headers show only the headers you set.
Content-Type,User-Agentand the signature headers are sent but not recorded. The full list is in What your endpoint receives. - A cron’s request body is shown before wrapping. If your cron payload is plain text, it is sent as
{"body": "..."}but recorded as the text you wrote (see Cron schedules). - Runs are deleted with their cron, job or queue. Deleting a cron deletes its execution history. Purging a dead-lettered job, or its automatic cleanup after the queue’s Dead letter retention, deletes its run.
Run status
A cron execution is in one of four states: Pending, Processing, Completed or Failed.
Completed means a response arrived. It doesn’t mean success: a cron that gets a 500 back is Completed, shown with a red status code, and has the failure reason http_server_error. Failed means there was no usable response (timeout, connection or DNS problems), an assertion failed, or the monthly limit was reached.
A run counts as successful only when a 2xx response arrived and no failure reason was set. For job statuses and retries, see Jobs.
Failure reasons
Every failed run gets one of these reasons. The dashboard shows the text in the Label column, for example in the Jobs list and on the Alerts page.
| Reason | Label | What happened | What to do |
|---|---|---|---|
timeout | Timeout | No complete response within the request timeout, or the connection couldn’t be opened within 10 seconds | Make the endpoint answer faster (reply first, then do the work), or raise the timeout (up to 300 seconds) |
connection_error | Connection error | The connection was refused, reset or unreachable | Check the server is up, listening on the right port, and that its firewall accepts outside traffic |
dns_error | DNS error | The hostname couldn’t be resolved | Check the domain spelling and its DNS records |
ssl_error | SSL/TLS error | The TLS handshake failed | Check the certificate is valid, not expired and has its full chain. The server must support TLS 1.2 or newer. |
http_client_error | Client error (4xx) | Your endpoint returned a 4xx status | Check the URL, method, auth headers and payload. The response body usually says what’s wrong. |
http_server_error | Server error (5xx) | Your endpoint returned 500 or higher | Check your server logs for the error at that time |
invalid_url | Invalid URL | The URL has no host, or uses a scheme other than http or https | Fix the URL |
assertion_failed | Assertion failed | A 2xx response arrived but a success assertion didn’t pass | The error message names the assertion. Compare it with the response body. |
limit_exceeded | Monthly limit reached | Your team reached its monthly request limit, so no request was sent | Upgrade, or wait for the next month. See How usage is counted. |
unknown | Unknown error | Anything else (see below) | Read the error message |
The most common causes of unknown:
- A redirect. Delay doesn’t follow redirects, so a
301,302,307or308is a failure. Use the final URL (checkhttps,wwwand trailing slashes). - “URL resolves to a blocked IP address”. The hostname points to a private or reserved address (such as
10.x,192.168.xor127.0.0.1). Delay only calls public addresses. - “Cannot resolve host”. The hostname has no public IPv4 address. Check its DNS records. Hosts that only have an IPv6 address can’t be called.
Job attempts that fail for any of these reasons are retried according to their queue’s settings, except limit_exceeded (see Queues). Crons never retry.
How usage is counted
Each run counts as one request toward your team’s monthly quota:
- every cron execution, scheduled or started with Run now;
- every job attempt, so a job that succeeds on its third try counts three times;
- failed runs, and runs blocked by the limit.
Callbacks and alert notifications don’t count. The count is per team and resets at the start of each calendar month, in UTC.
| Plan | Requests per month | Warning at |
|---|---|---|
| Free | 1,000 | 800 (80%) |
| Starter | 20,000 | 18,000 (90%) |
| Pro | 75,000 | 67,500 (90%) |
| Business | 500,000 | 450,000 (90%) |
| Enterprise | 5,000,000 | 4,500,000 (90%) |
You can see this month’s count on the Usage tab.
At the warning level, Delay adds one “Limit warning” alert per month to the Alerts page. It is shown in the app only, not sent by email, Slack or Discord.
At the limit, every new run fails at once with limit_exceeded, and no request is sent:
- Jobs are not retried and don’t go to the dead letter queue. No callback is sent.
- Crons stay on their schedule and record a failed run each time they come due.
- The API still accepts new jobs and crons with a
201. The limit is checked when a run starts, not when you create it.
The count is refreshed about once a minute, so a busy team can go slightly over its limit before runs are blocked.
Next steps
- Debug a failed run: find a failed run and read it.
- Success assertions: turn a misleading 200 into a failure.
- Write endpoints Delay can call: avoid timeouts, redirects and duplicates.
- Troubleshooting: symptoms and fixes.