basecamp/kamal · warning
Retrying DNS for #{hostname} (attempt #{attempts}/#{retries}
Error message
Retrying DNS for #{hostname} (attempt #{attempts}/#{retries}) in #{format("%0.2f", delay)}s: #{error.message} What it means
Kamal patches SSHKit so SSH operations retry transient DNS failures: with_dns_retry rescues Resolv::ResolvError/ResolvTimeout or SocketError messages matching a DNS pattern, logs this warning, and sleeps with exponential backoff plus jitter before retrying. The message (sshkit_with_ext.rb:89) is a warning, not an exception — it tells you attempt N of config.dns_retries is about to be retried after a delay. The original error is re-raised only once attempts exceed the retry budget.
Source
Thrown at lib/kamal/sshkit_with_ext.rb:89
end
class SSHKit::Backend::Netssh
module DnsRetriable
DNS_RETRY_BASE = 0.1
DNS_RETRY_MAX = 2.0
DNS_RETRY_JITTER = 0.1
DNS_ERROR_MESSAGE = /getaddrinfo|Temporary failure in name resolution|Name or service not known|nodename nor servname provided|No address associated|failed to look up|resolve/i
def with_dns_retry(hostname, retries: config.dns_retries, base: DNS_RETRY_BASE, max_sleep: DNS_RETRY_MAX, jitter: DNS_RETRY_JITTER)
attempts = 0
begin
attempts += 1
yield
rescue => error
raise unless retryable_dns_error?(error) && attempts <= retries
delay = dns_retry_sleep(attempts, base: base, jitter: jitter, max_sleep: max_sleep)
SSHKit.config.output.warn("Retrying DNS for #{hostname} (attempt #{attempts}/#{retries}) in #{format("%0.2f", delay)}s: #{error.message}")
sleep delay
retry
end
end
private
def retryable_dns_error?(error)
case error
when Resolv::ResolvError, Resolv::ResolvTimeout
true
when SocketError
error.message =~ DNS_ERROR_MESSAGE
else
error.cause && retryable_dns_error?(error.cause)
end
end
def dns_retry_sleep(attempt, base:, jitter:, max_sleep:)View on GitHub (pinned to eee0083b38)
Solutions
- If occasional, no action: the built-in retry with backoff usually recovers and the deploy continues.
- Make resolution reliable: fix DNS records or /etc/hosts entries for the hosts, or reference hosts by IP in deploy.yml.
- Raise the budget: set `dns_retries: <n>` in the Kamal config if hosts are slow to become resolvable (boot lag, dynamic DNS).
- If resolution never succeeds, fix the resolver itself (systemd-resolved, VPN split-DNS, Docker DNS) — retries cannot cure a permanent failure once attempts exceed the limit.
Example fix
// before
# deploy.yml — SSH races slow DNS while hosts boot
servers:
web:
hosts: [app-1.example.com]
// after
dns_retries: 10
servers:
web:
hosts: [203.0.113.10] # or pin IP / pre-warm DNS Defensive patterns
Strategy: retry
Validate before calling
# Pre-resolve hosts before deploying
require 'resolv'
Resolv::DNS.open { |dns| dns.getaddress('app-1.example.com') } # raises if unresolvable Try / catch
begin
on(hosts) { execute :uptime }
rescue SocketError, Resolv::ResolvError => e
# with_dns_retry already exhausted its budget — fix resolution, then re-run
abort "DNS failed after retries: #{e.message}"
end Prevention
- Pre-warm DNS or use IPs for freshly booted hosts
- Set dns_retries in the Kamal config sized to host boot time
- Fix split-DNS, VPN, and systemd-resolved issues on the deploy box
- Treat the warning as a signal: occasional retries are fine, constant retries mean a broken resolver
When it happens
Trigger: Any SSH command to a hostname (deploy, app boot, healthchecks over SSH) while name resolution intermittently fails — getaddrinfo / 'Name or service not known' style errors — and retries remain: hosts or containers still booting, flaky VPN or systemd-resolved, Docker embedded DNS limits, or resolver timeouts under load in CI.
Common situations: Deploying immediately after spinning up hosts whose DNS records lag; internal DNS that is slow or rate-limited; network or VPN switching mid-deploy; parallel SSH connections stressing the local resolver.
Related errors
- Local registry with remote builder requires an SSH URL (e.g.
- Failed to sync Bitwarden
- Hook `#{hook}` failed:\n#{e.message}
- Raw is not compatible with interactive
- Failed to get endpoint for #{role} on #{host}, did the conta
AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21).
Data as JSON: /api/errors/c6fefb59ea11cb35.
Report an issue: GitHub.