An empty result is not the same as a successful request that found nothing. When a crt.sh query returned errors—or data in an unexpected shape—Timothy Kelvin’s certificate-monitoring actor showed how retries, timeouts and response validation need to work together. The practical lesson for developers is to distinguish “no data” from “no successful response” before a monitoring tool reports either one.
How an apparent empty result became an availability problem
Kelvin describes building an Apify actor that watches Certificate Transparency logs for certificates issued to a domain and its subdomains. Its data source, crt.sh, is a free, community-run CT search service. In his account, requests under load sometimes returned bare HTML error pages instead of JSON; the same query could produce a 404 on one attempt and real results on another. He also reports seeing 502, 503 and 504 responses. These are observations from his actor and query, not a promise about crt.sh’s current behavior. Kelvin’s account
As an Amazon Associate I earn from qualifying purchases.
That variability matters because a monitoring tool can mistake a failed lookup for a finding of zero certificates. An HTTP response does not become a valid “no results” answer merely because it is readable or arrives with a status code. The client needs to check both whether the request succeeded and whether the body has the expected format before interpreting its contents.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Retry transient failures, not every unsuccessful response
Kelvin initially used four attempts with exponential backoff. He later reported six consecutive 502 responses before one request succeeded, and said his actor’s rolling 30-day failure rate had reached “something like 46%.” Those figures describe his particular actor during the reported period, not crt.sh’s overall reliability. Under load, he also reported successful requests taking 10–20 seconds. He increased his retry count to eight and capped the backoff, but does not give an exact delay schedule.
#1 Best Overall
Retries should follow the semantics of the endpoint rather than treat every non-success as temporary. For CT log protocol responses, RFC 9162 says clients SHOULD treat 500 Internal Server Error and 503 Service Unavailable as transient failures and MAY retry the same request later. It also says a 503 MAY carry a Retry-After header specifying a minimum wait. The RFC says clients SHOULD treat 4xx responses as request problems and not resubmit without modifying the request. This is guidance for CT log protocol responses; it does not formally define how crt.sh’s website or search endpoint behaves.
Kelvin’s observed 404 is a reason to avoid equating that status with “no certificates found,” but it is not evidence that every 404 should be retried. A 404 may indicate a request or endpoint problem; the client should decide based on the service contract and the response itself. If a response is an unexpected error page, record it as a failed lookup rather than converting it into a valid empty dataset.
Bound retries by attempts and elapsed time
Exponential backoff can space requests farther apart after repeated failures and reduce pressure on a shared service. It should still have a cap or an overall time budget: a growing delay can otherwise keep a monitoring job open longer than is useful. An attempt limit alone is not enough if an individual request can hang indefinitely, while a per-request timeout alone does not prevent an endless retry loop.
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errorsThe CT community’s fetch guidance recommends exponential backoff as one possible response to rate limiting. It also notes that rate limits can vary and advises clients to re-evaluate request volume in light of recent server responses. Where a response includes Retry-After, account for its minimum wait rather than retrying sooner.
One crt.sh mailing-list post from 2020 reported throttling at 60 requests per IP per minute, with a burst of five. That is a historical report, not a verified current limit; clients should not hard-code it as crt.sh’s present policy. The mailing-list post
Make a hung request become a retryable failure
Kelvin found that plain fetch() in his setup did not impose a timeout. If a request never resolves, the code waiting for it cannot reach the branch that handles a failed response. As he put it: “If a request never resolves, it never reaches the point where my retry logic would even kick in.” He added an AbortController with a timeout for each attempt so a hung request would be aborted and could enter the retry path. His account does not specify the timeout duration.
Rank #3
A robust client therefore needs two separate bounds: a per-attempt deadline that turns a stalled network operation into a failure, and a total retry budget that limits how long the whole lookup can run. Keep the timeout and retry policy appropriate to the expected response time and the monitoring job’s deadline; Kelvin’s reported 10–20-second successful responses under load are an anecdotal observation, not a universal timeout recommendation.
Free tools Windows power users keep installed
One-click scans. No signup required.
Validate successful responses before trusting their data
HTTP success alone did not protect Kelvin’s actor from a silent data-quality failure. The actor’s date filter and newest-first sort depended on an entry_timestamp field. When that field disappeared from the JSON output for the query, new Date(undefined) >= startDate evaluated false for every entry. The actor returned zero results without throwing—even though the request had not failed in the usual HTTP sense.
Kelvin switched to not_before as a proxy for log time. His account does not establish that the two timestamps are interchangeable for every application, so a client should verify the meaning and suitability of any substitute field for its own use case.
For a domain or certificate monitor, response validation should include checking the expected content type and structure, confirming required fields exist before filtering or sorting, and treating an implausible zero-result response as something to investigate rather than automatically as a clean bill of health. Preserve enough diagnostics—status, response type, and validation failure—to distinguish a genuine empty result from an upstream or schema problem.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Design the retry policy as a complete decision
Retry count and backoff are only part of the design. A useful policy specifies which failures are retryable, how long one attempt may run, how long the whole lookup may take, how server-directed waits are handled, and how request volume responds to rate-limit signals. It also defines what makes a successful response trustworthy.
| Design choice | What to decide |
|---|---|
| Retryable failures | Separate likely transient server or network failures from request errors. Use the endpoint’s contract; RFC 9162’s 500/503 and 4xx guidance applies to CT log protocol responses, not as a formal crt.sh website contract. |
| Time bounds | Set both a per-attempt timeout and an overall attempt or elapsed-time budget so neither a stalled request nor repeated failures can hold a job indefinitely. |
| Retry delay | Use bounded backoff where appropriate and honor a Retry-After minimum wait if supplied. |
| Request volume | Reassess concurrency and request frequency when responses indicate rate limiting; do not assume a historical rate figure remains current. |
| Response validation | Check expected body format, required fields, and whether the result count is plausible before treating the lookup as authoritative. |
The CT community also warns that logs may return fewer entries than requested. A client fetching log entries should inspect how many arrived and advance its index based on the actual response count, rather than assuming it received the full requested batch. That guidance concerns CT log fetching; it should not be confused with a guarantee about crt.sh search results. CT community fetch guidance
Best Value
- Used Book in Good Condition
What to report when a lookup fails
For an operational tool, “zero certificates” and “could not complete the lookup” are different outcomes and should be visible as such. Return a result only after the response passes transport, status and schema checks. If the attempt budget expires, report an unavailable or incomplete lookup, along with useful diagnostics, instead of publishing an empty result that downstream users could mistake for verified absence.
Kelvin’s case is a reminder that retries are not just a loop around a request. They are part of a correctness boundary: transient failures need a bounded second chance, stalled operations need deadlines, and apparently successful responses still need validation before they can support a conclusion.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




