Recommended Free Tools
Go does not provide a general “retry every failed HTTP request” switch. http.Transport performs only a narrow set of transport-level retries; it does not retry arbitrary 5xx responses or give your application a policy for timeouts, backoff, idempotency, and request bodies. Reliable retries require an explicit, bounded loop that knows whether the operation can safely be repeated.
What Go retries automatically—and what it does not
http.Client handles request execution, redirects, cookies, and its configured timeout. The request context controls connection acquisition, sending, and response handling. A Client.Timeout covers connection setup, redirects, and reading the response body; a value of zero means no timeout.
The underlying http.Transport may retry a network error when a previously successful connection is reused and the request is considered idempotent. Its documented method recognition includes GET, HEAD, OPTIONS, and TRACE. A request with an Idempotency-Key or X-Idempotency-Key can also be recognized as idempotent. If a request has a body, transport replay requires a defined Request.GetBody (or no body). These rules are deliberately narrow: they do not retry a server response such as 503, nor do they define how many attempts your business operation should make.
Decide whether repeating the operation is safe
Start with HTTP method semantics
HTTP defines GET, HEAD, PUT, DELETE, OPTIONS, and TRACE as idempotent by intended effect. Repeating an idempotent request should produce the same intended state, although the response itself can differ. POST is not idempotent by default.
#1 Best Overall
- Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
- Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
- Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
- Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
- 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
Check the real application effect
Method names are not enough. A GET that triggers an email or mutation is not safe to repeat, while a service may make a POST safely repeatable with a documented deduplication contract. The hardest case is an ambiguous write: the server may have committed it, but the response was lost. Retrying without an operation identity can create a duplicate charge, order, or job.
Use an idempotency key for writes
For a non-idempotent write, retry only when the remote API honors an idempotency key (or equivalent token). Generate one logical operation ID before the first attempt and send that same value on every attempt. Do not generate a new key inside the retry loop.
Classify failures before retrying
Retry only failures that are plausibly transient and for which repeating the operation is safe.
- Usually transient: temporary connection resets, DNS or connect timeouts, and selected overload or server errors such as
429,502,503, or504, subject to the API contract. - Usually permanent: malformed URLs, invalid request data, failed authentication, authorization failures, and other client errors that will not change without new input or credentials.
- Ambiguous: a timeout or connection failure after a request may have reached the server. Treat it as a completed-or-not-knowable write and rely on idempotency or a status query.
If the response includes Retry-After, parse its delay or HTTP date and honor it, but cap the resulting wait by both your policy and the caller’s remaining deadline. A malformed or excessive value should not force an unbounded sleep.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchA bounded, cancelable retry loop
The following example retries a JSON operation with a caller-owned deadline, exponential backoff, full jitter, status classification, a stable idempotency key, and a fresh request body on every attempt. The values are examples, not universal defaults.
Rank #2
- 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
- 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
- Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
- 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
- What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.
package main
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"math/rand"
"net/http"
"strconv"
"strings"
"time"
)
type RetryPolicy struct {
MaxAttempts int
BaseDelay time.Duration
MaxDelay time.Duration
}
func retryableStatus(code int) bool {
switch code {
case http.StatusTooManyRequests, http.StatusBadGateway,
http.StatusServiceUnavailable, http.StatusGatewayTimeout:
return true
default:
return false
}
}
func retryAfter(value string, now time.Time) (time.Duration, bool) {
value = strings.TrimSpace(value)
if value == "" { return 0, false }
if seconds, err := strconv.Atoi(value); err == nil && seconds >= 0 {
return time.Duration(seconds) * time.Second, true
}
if when, err := http.ParseTime(value); err == nil {
if when.After(now) { return time.Until(when), true }
return 0, true
}
return 0, false
}
func wait(ctx context.Context, d time.Duration) error {
timer := time.NewTimer(d)
defer timer.Stop()
select {
case <-timer.C:
return nil
case <-ctx.Done():
return ctx.Err()
}
}
func postJSON(ctx context.Context, client *http.Client, endpoint string, payload any, key string, p RetryPolicy) (*http.Response, error) {
if p.MaxAttempts < 1 { return nil, errors.New("MaxAttempts must be positive") }
if p.BaseDelay < 0 || p.MaxDelay < 0 { return nil, errors.New("delays cannot be negative") }
data, err := json.Marshal(payload)
if err != nil { return nil, err }
for attempt := 1; attempt <= p.MaxAttempts; attempt++ {
req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(data))
if err != nil { return nil, err }
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Idempotency-Key", key)
resp, err := client.Do(req)
if err == nil {
if !retryableStatus(resp.StatusCode) || attempt == p.MaxAttempts {
return resp, nil // caller owns and must close the body
}
serverDelay, hasServerDelay := retryAfter(resp.Header.Get("Retry-After"), time.Now())
// Drain only a bounded amount before closing; never read an unbounded error body.
_, _ = io.CopyN(io.Discard, resp.Body, 64*1024)
resp.Body.Close()
delay := p.BaseDelay
for i := 1; i < attempt; i++ {
if delay >= p.MaxDelay/2 { delay = p.MaxDelay; break }
delay *= 2
}
if delay > p.MaxDelay { delay = p.MaxDelay }
if hasServerDelay && serverDelay > delay { delay = serverDelay }
if delay > p.MaxDelay { delay = p.MaxDelay }
if delay > 0 { delay = time.Duration(rand.Int63n(int64(delay) + 1)) }
if err := wait(ctx, delay); err != nil { return nil, err }
continue
}
if attempt == p.MaxAttempts { return nil, err }
// Network errors are retryable only if repeating this operation is safe.
delay := p.BaseDelay
for i := 1; i < attempt; i++ {
if delay >= p.MaxDelay/2 { delay = p.MaxDelay; break }
delay *= 2
}
if delay > p.MaxDelay { delay = p.MaxDelay }
if delay > 0 { delay = time.Duration(rand.Int63n(int64(delay) + 1)) }
if err := wait(ctx, delay); err != nil { return nil, err }
}
return nil, errors.New("retry loop ended unexpectedly")
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
client := &http.Client{Timeout: 10 * time.Second}
resp, err := postJSON(ctx, client, "https://api.example.test/orders",
map[string]any{"sku": "A-17", "quantity": 1}, "order- operation-123",
RetryPolicy{MaxAttempts: 4, BaseDelay: 200 * time.Millisecond, MaxDelay: 3 * time.Second})
if err != nil { panic(err) }
defer resp.Body.Close()
fmt.Println(resp.StatusCode)
}
In production, seed a per-process random source rather than relying on a globally shared source, and record the attempt number, final status, elapsed time, and cancellation cause. If the server’s Retry-After exceeds your cap, choose explicitly whether to stop or use the cap; the example caps it.
Request bodies must be replayable
An io.Reader is a stream. Once consumed, it is not automatically restored for the next attempt. Marshal immutable data once and construct a new reader and request each time, as above. For other payloads, retain bytes, reopen a file, or provide an explicit rewind function. Go’s transport can replay a body only when GetBody is available; do not assume an arbitrary reader is safe.
Always close every response body. If discarding a retryable response, drain only a bounded amount before closing when connection reuse is useful. Never read an unlimited error page just to keep a connection in the pool.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsDeadlines, cancellation, and total budget
Use the caller’s context as the total operation budget. Create requests with http.NewRequestWithContext, and make backoff waits select on ctx.Done(). Cancellation must stop both an in-flight request and a pending delay. A per-request client timeout can still be useful, but it is not a substitute for an overall deadline: multiple attempts can otherwise exceed what the caller intended.
Before sleeping, compare the proposed delay with the remaining deadline. If no useful attempt can fit, return the context error rather than starting another request. Do not continue retrying after the caller has stopped waiting.
Rank #3
- Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
- Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
- Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
- Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
- What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.
Backoff, jitter, and load control
Exponential backoff increases the interval after each failure; a cap prevents a single delay from becoming unbounded. Full jitter chooses a random delay between zero and the calculated cap. Without jitter, many clients that observed the same outage can wake together and recreate a traffic spike. A finite attempt limit is also essential: unlimited retries can turn a dependency outage into sustained load and unexpected cost.
Choose the attempt count and delays from the operation’s latency objective, server guidance, and dependency behavior. There is no universally correct numeric configuration. For latency-sensitive reads, a small budget may be appropriate; a payment operation may instead prefer a status lookup after an ambiguous timeout.
Hand-written loop or a retry library?
| Concern | Direct loop | go-retryablehttp |
|---|---|---|
| Policy control | Complete control over statuses, headers, and business rules. | Built-in retry checks and backoff that you can customize. |
| Request replay | You implement body recreation and operation identity. | Provides documented request-body rewind mechanisms; verify behavior for your payload and current module version. |
| Cancellation and budget | Visible in your code; ensure every wait and request uses context. | Confirm the library’s context and timeout behavior matches your total budget. |
| Integration cost | No dependency, but more code to maintain. | Less policy plumbing, plus a dependency and its versioning. |
| SDK interaction | You must account for retries already performed by an SDK. | Still can multiply attempts when wrapped around an SDK. |
Use a small direct loop when the service rules are simple and explicit. A retry package is useful when standardized backoff, classification, and body replay justify the dependency. Read its current module documentation and test it against the API’s idempotency contract.
Avoid stacked retry policies
The AWS SDK for Go v2 has its own retryer, maximum-attempt setting, and rate limiting. If you add an outer loop around an SDK call, calculate the combined worst-case attempts and delay. Two independent policies can multiply traffic and exceed the caller’s deadline. Apply one clear budget at the boundary where you can observe the complete operation.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Common failures and fixes
“My POST ran twice”
The operation was retried without a server-supported idempotency key, or a new key was generated for each attempt. Reuse one key for the logical operation and confirm the server’s deduplication semantics.
Rank #4
- Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
- Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
- Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
- Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
- Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft
“The second attempt sends an empty body”
The original reader was consumed. Store the payload or implement a rewind/open function, then build a fresh request per attempt.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →“Retries ignore cancellation”
The code used time.Sleep. Replace it with a timer that selects between timer completion and ctx.Done().
“A 400 response keeps retrying”
The classifier is too broad. Retry only documented transient statuses and transport errors; return validation and authentication failures immediately.
“The service is overwhelmed during an outage”
There is no cap, jitter, or global budget. Add all three, honor bounded Retry-After, and monitor attempt counts.
“Connections are not reused”
A response body was not closed, or an unbounded body read was attempted. Close every body and drain only a small, safe amount when discarding it.
Best Value
- 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
- Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
- Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
- HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
- What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.
Or skip the browser setup
Retrying HTTP requests is separate from taking website screenshots, but if your workflow also needs a reliable screenshot endpoint, ScreenshotNeo avoids maintaining browser workers and consent-banner handling. A single GET returns a PNG, JPEG, WebP, or PDF; failed loads, bot checks, blank pages, timeouts, and cache hits are not billed, and an MCP server lets AI agents call screenshot tools.
Use the API call documented at ScreenshotNeo’s API documentation:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Cookie and consent banners, newsletter popups, and chat widgets are removed before capture. The free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
FAQ
Does http.Client retry every 500 response?
No. Application-level status retries require your own policy or a library.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →Should every timeout be retried?
No. First determine whether the operation is safe to repeat and whether the timeout leaves its outcome ambiguous.
Can I retry a request from multiple goroutines?
Yes, provided each goroutine has its own request state, shares a bounded context, and does not duplicate a non-idempotent operation. Coordinate concurrency separately from per-request retries.
Frequently Asked Questions
Does http.Client retry every 500 response?
No. Application-level status retries require your own policy or a library.
Should every timeout be retried?
No. First determine whether the operation is safe to repeat and whether the timeout leaves its outcome ambiguous.
Free tools Windows power users keep installed
One-click scans. No signup required.
Can I retry a request from multiple goroutines?
Yes, provided each goroutine has its own request state, shares a bounded context, and does not duplicate a non-idempotent operation.
The Bottom Line
Safe Go retries are bounded, cancelable, status-aware, and built around replayable request data and a stable idempotency key for writes. Treat transport retries as a narrow safety net—not an application retry strategy.
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.

