A failed lookup is not the same thing as a successful lookup with no matches. In a case study about an Apify actor that monitors Certificate Transparency (CT) logs, Timothy Kelvin found that confusing those outcomes—and trusting a field that had silently disappeared—could make a monitoring tool report the wrong result. The practical lesson is to make retries bounded and selective, put a timeout on each attempt, and validate the response before treating it as data.
How an empty result became a misleading result
Kelvin built an Apify actor to watch CT logs for certificates issued to a domain and its subdomains. The actor queried crt.sh, a free, community-run CT search service. In the calls he describes, crt.sh sometimes returned bare HTML error pages instead of JSON. He also reported that an identical query returned a 404 on one attempt and actual results on another, along with 502, 503, and 504 responses. These are observations from his actor and query—not a guarantee of how crt.sh behaves for other clients or today. Kelvin’s case study
The 404 illustrates a crucial distinction: a response that looks like “no results” may not be a successful search response at all. A client should establish that the HTTP response succeeded and that its body has the expected format before interpreting an empty result as meaningful. Kelvin’s experience is evidence that his observed 404 did not reliably mean “no matching certificates”; it is not a rule that every 404 from every endpoint should be retried.
There was a second, quieter failure. The actor’s newest-first ordering and date filter relied on an entry_timestamp field. When that field disappeared from the JSON for the query, the expression new Date(undefined) >= startDate evaluated to false for every entry. The request could therefore appear to succeed while the actor returned zero results. Kelvin switched to not_before as a proxy for log time, but that does not establish that the two timestamps are interchangeable for every monitoring task.
#1 Best Overall
What CT guidance says about retrying
Retry policy depends on the endpoint and protocol. RFC 9162’s CT log protocol guidance says clients SHOULD treat 500 Internal Server Error and 503 Service Unavailable as transient failures, and MAY retry the same request later without modification. A 503 MAY include Retry-After, which specifies a minimum wait before another attempt. The same section says clients SHOULD treat 4xx responses as a request problem and should not resubmit them without modifying the request. This is guidance for CT log protocol responses; it does not formally specify the behavior of crt.sh’s HTML search website. RFC 9162, section 4.1.1
For CT infrastructure more broadly, the community’s fetch guidance notes that servers may rate-limit clients, recommends exponential backoff as one possible response, and advises clients to reassess request volume in light of recent server responses. It also warns that a CT log may return fewer entries than requested: clients should inspect the count actually received and advance indexes by that count, rather than assuming the requested amount arrived. CT community fetch guidance
A crt.sh mailing-list post dated January 27, 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. Treat rate limits as changeable and tune clients in response to current server behavior rather than coding that old figure as a service contract. 2020 crt.sh mailing-list post
Build retries that terminate and respect the service
Classify failures before retrying
Separate transport failures, timeouts, transient server responses, client/request errors, and valid responses with no matches. Retry only failures that are plausibly temporary for the endpoint you are calling. For a CT log protocol client, RFC 9162 distinguishes 500/503 from 4xx; for a website endpoint such as crt.sh, do not assume that protocol guidance is a formal service guarantee. In particular, Kelvin’s intermittent 404 is a reason to validate what that endpoint returned, not blanket permission to retry all 404s.
Rank #3
Set both per-attempt and whole-operation limits
A retry count alone does not guarantee completion: one attempt may hang indefinitely. Kelvin found that plain fetch() in his setup did not impose a timeout, so he used an AbortController with a per-attempt timeout, converting a hung request into a failure his retry logic could handle. He does not state the timeout duration or a specific backoff schedule, so neither should be inferred from his account.
Use an attempt budget and an elapsed-time budget together. Exponential backoff spaces retries farther apart; a cap prevents the delay from growing without bound. If a response includes Retry-After, wait at least the indicated minimum before retrying. Ensure the combined request timeouts and waits still fit the task’s deadline; otherwise, stop and report an incomplete lookup rather than silently calling it empty.
Adapt volume when responses indicate pressure
Backoff helps avoid adding load during a service problem, but retries can still amplify traffic if many workers make them at once. Observe rate-limit and server responses, then reduce request volume or concurrency when they indicate pressure. The CT community guidance specifically recommends reevaluating request volume against recent server responses; it does not give one universal request rate that is safe for every service.
What Kelvin’s numbers do—and do not—show
Kelvin reported starting with four attempts and exponential backoff. In his actor, he then observed six consecutive 502 responses before a request succeeded, and described the rolling 30-day failure rate as “something like 46%.” He increased the retry count to eight and capped the backoff; he also said successful responses could take 10–20 seconds under load. These figures describe his particular actor and reported period, not crt.sh’s overall reliability, a current service-wide failure rate, or a recommended retry configuration for other clients. Kelvin’s case study
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Best Value
- Used Book in Good Condition
His central timeout observation is broader than those numbers: “If a request never resolves, it never reaches the point where my retry logic would even kick in.” A timeout is what makes that stalled attempt observable to the retry policy; the retry policy then needs to decide whether another attempt is appropriate and whether enough time remains.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Validate the data after a successful response
HTTP success alone does not establish that a monitoring result is trustworthy. Check that the body parses as the expected format and that fields required by filtering, sorting, or pagination are present and usable. If a query that normally returns entries suddenly produces zero, investigate whether the query truly has no matches, whether the response shape changed, or whether a filter is excluding entries because a value is missing.
- Distinguish a valid empty result from an error status, unexpected HTML, malformed JSON, or missing required fields.
- For date filters, define what should happen when the timestamp is absent or invalid instead of allowing a comparison to discard every entry silently.
- For CT log pagination, base index advancement on the number of entries actually returned, not the requested count.
- Expose failure and validation outcomes separately from “no matches,” so monitoring consumers can tell incomplete data from a genuine empty search.
Kelvin’s switch to not_before addressed his actor’s missing-field problem, but a timestamp’s meaning depends on the use case. Confirm that a substitute field represents the event your tool intends to measure before using it for ordering or time-window logic.
Quick Recap
A practical retry-policy checklist
- Retry classification: Which transport errors and status codes are transient for this specific endpoint? Which indicate a request problem that needs correction?
- Attempt timeout: How long may one network attempt run before it is cancelled and classified?
- Overall deadline: What is the maximum elapsed time for the complete lookup, including all waits and attempts?
- Delay policy: Is backoff exponential and capped, and does the client honor a server-provided
Retry-Afterminimum? - Load response: Do rate limits or repeated server errors cause concurrency or request volume to fall?
- Response validation: Are content type, parseability, required fields, and plausible result counts checked before reporting success?
- Outcome reporting: Can downstream users distinguish no matches from a failed, timed-out, or structurally invalid lookup?
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.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.

