Bundle resolver does not retry on network-level transient errors (TCP timeout, connection reset, EOF)
Problem
The bundle resolver's retry/backoff mechanism (configured via bundleresolver-config) only retries on HTTP response codes (429, 5xx). It does not retry on network-level transient errors such as:
- TCP connection timeouts (
dial tcp ... i/o timeout) - Connection resets (
connection reset by peer) - Broken pipes (
broken pipe) - EOF errors (server closed connection mid-transfer)
- TLS handshake timeouts
These are all recoverable, transient errors that occur frequently in production environments with shared egress proxies, registry mirrors behind load balancers, or cloud NAT gateways with connection limits.
Root Cause
The retry logic in go-containerregistry's transport.Retry relies on net.Error.Temporary() to identify retryable network errors. However, Go deprecated Temporary() (it returns false for most errors since Go 1.18+), so network-level errors are no longer classified as retryable.
The Timeout() check and connection-reset detection were added in newer go-containerregistry versions, but may not be present in the version bundled with current Tekton releases.
Observed Behavior
With bundleresolver-config set to:
backoff-duration: "15s"
backoff-factor: "2.0"
backoff-steps: "10"
backoff-cap: "15m"
fetch-timeout: "2m"A bundle reference pointing to a host that causes a TCP timeout fails immediately after the first dial timeout (~30s) with no retry:
cannot retrieve the oci image: Get "https://...": dial tcp ...: i/o timeoutIn contrast, if the registry returns HTTP 503, the backoff configuration would be respected.
Expected Behavior
Network-level transient errors should be retried with the same backoff configuration as HTTP 5xx responses. At minimum:
Timeout()errors (connection timeouts, read timeouts)ECONNRESET/ connection reset by peerEPIPE/ broken pipe- Unexpected EOF
Suggested Fix
Either:
- In go-containerregistry: Update
transport.Retry'sshouldRetryto checkTimeout()and recognize connection-reset/EOF errors as retryable (some newer versions may already do this). - In Tekton resolvers: Add a resolver-level retry loop that re-attempts the full resolution on any error (not just HTTP-level errors), using the configured backoff parameters.
Related
- #8571 — Retry failed resolvers (general retry support for all resolvers)
-- Gal's Cursor
Source: tektoncd/pipeline