Back to blog
Networking & DNS September 15, 2026

Could Not Resolve Hostname (nodename nor servname provided): POSIX Socket & DNS Troubleshooting Guide

Automate WhatsApp Alerts
Start Free ➔

You run a database migration script, start a local Docker container, or initiate an API call in Python, Go, or Node.js. Instead of establishing a connection, the runtime crashes instantly with a cryptic error:

socket.gaierror: [Errno 8] nodename nor servname provided, or not known

or in curl / Git on Linux:

curl: (6) Could not resolve host: api.example.com
fatal: unable to access 'https://github.com/org/repo.git/': Could not resolve host: github.com

Why does the error mention both "nodename" and "servname"? And why does a query work in your browser or with dig, but fail when invoked from inside an application, container, or CI/CD pipeline?

The answer lies in how operating systems and standard C libraries (glibc, musl, macOS libSystem) implement the POSIX getaddrinfo() system call. In modern network programming, hostname lookup is coupled with service/port translation and name service switch (nsswitch) pipelines.

In this deep-dive guide, we decode the POSIX getaddrinfo() resolver architecture, isolate nodename (host) vs servname (port/service) failures, troubleshoot Kubernetes ndots:5 query amplification, diagnose broken IPv6 Happy Eyeballs routing, and provide a definitive 10-step triage runbook.


1. Decoding nodename nor servname provided, or not known

When an application attempts to open a network socket to api.example.com:443, it does not immediately dispatch a DNS packet. It invokes the standard C library function getaddrinfo() (or the deprecated gethostbyname()).

int getaddrinfo(const char *node,     // "nodename": Hostname or IP (e.g., "api.example.com")
                const char *service,  // "servname": Port or service name (e.g., "443" or "https")
                const struct addrinfo *hints,
                struct addrinfo **res);
                 THE POSIX getaddrinfo() RESOLUTION PIPELINE

    Application Call: getaddrinfo("api.example.com", "https", ...)
                                 │
                 ┌───────────────┴───────────────┐
                 ▼                               ▼
      1. Nodename Resolution            2. Servname Resolution
         (Translates Host -> IP)           (Translates Service -> Port)
                 │                               │
         ├── Check /etc/hosts            ├── Is it numeric string? ("443")
         ├── Query systemd-resolved      └── Lookup /etc/services ("https" -> 443)
         └── Dispatch UDP/TCP DNS                │
                 │                               ▼
                 ▼                       Port = 443 (htons)
         IP = 198.51.100.10                      │
                 │                               │
                 └───────────────┬───────────────┘
                                 ▼
                     Returns struct addrinfo 
                     (Ready for socket() & connect())

What the Error Codes Actually Mean

If getaddrinfo() fails, it returns a non-zero error constant defined in <netdb.h>:

POSIX Return CodeError String (macOS / BSD)Error String (Linux / glibc)Root Cause
EAI_NONAMEnodename nor servname provided, or not knownName or service not knownThe hostname (node) does not resolve in DNS/hosts, OR an invalid service was supplied.
EAI_SERVICEservname not supported for ai_socktypeServname not supported for ai_socktypeThe service name does not exist in /etc/services for the requested socket type (SOCK_STREAM).
EAI_AGAINResource temporarily unavailableTemporary failure in name resolutionDNS server timeout; network unreachable; DNS rate limit or packet loss.
EAI_FAILNon-recoverable failure in name resolutionNon-recoverable failure in name resolutionAuthoritative nameserver returned SERVFAIL or DNSSEC validation collapsed.

2. Common Root Causes: Why It Breaks

Use this diagnosis table to classify why your specific environment is failing:

                               COMMON FAILURE MATRIX
  ┌─────────────────────────────────┬────────────────────────────────────────┐
  │ Failure Vector                  │ Root Cause Mechanism                   │
  ├─────────────────────────────────┼────────────────────────────────────────┤
  │ 1. URL Passed Instead of Host   │ Passing "https://example.com" as node  │
  │ 2. Invalid Port/Service String  │ Passing ":443" or "http//" as service  │
  │ 3. Trailing Spaces / Hidden CR  │ Hidden "\r" from Windows .env files   │
  │ 4. Kubernetes ndots:5 Storm     │ External domains queried 5x across K8s │
  │ 5. Docker 127.0.0.11 Isolation  │ Container lacks bridge DNS forwarder   │
  │ 6. Broken IPv6 (AAAA) Route     │ AAAA resolves, but host lacks IPv6 exit│
  │ 7. VPN Split-DNS Leak           │ Corporate nameserver unreachable on tun│
  └─────────────────────────────────┴────────────────────────────────────────┘

1. The "Full URL Passed as Hostname" Trap

The single most common developer error occurs when an application client (e.g. database driver, Redis client, or Python urllib) expects a pure hostname, but receives a full URI string:

# ❌ INCORRECT: getaddrinfo tries to look up the entire string as a DNS record!
db_host = "postgres://db.prod.internal:5432/main"
socket.getaddrinfo(db_host, 5432)
# -> socket.gaierror: [Errno 8] nodename nor servname provided, or not known

# ✅ CORRECT: Strip scheme, port, and path before passing to socket
db_host = "db.prod.internal"
socket.getaddrinfo(db_host, 5432)

2. The Windows CRLF (\r) Environment Variable Trap

When deploying applications from Windows to Linux Docker containers or CI/CD runners, .env files often retain Windows CRLF line endings.

  • The environment variable becomes DB_HOST="db.example.com\r".
  • The resolver attempts to query db.example.com\r in DNS, which fails instantly with EAI_NONAME.

3. Step-by-Step Diagnostic Workflow

Follow this ordered diagnostic sequence to pinpoint where name resolution is breaking:

# Step 1: Validate direct DNS resolution using public resolvers
dig +noall +answer +comments api.example.com @1.1.1.1

# Step 2: Test resolution through the local OS resolver stack (glibc NSSwitch)
getent hosts api.example.com

# Step 3: Inspect local nameserver configuration
# On Linux:
cat /etc/resolv.conf
# On systemd-resolved systems:
resolvectl status
# On macOS:
scutil --dns

# Step 4: Test independent IPv4 and IPv6 connectivity
curl -4 -v https://api.example.com/health
curl -6 -v https://api.example.com/health

4. Reproducing & Testing with Python getaddrinfo()

Use this standalone Python script to test how the operating system's C library resolves your target host and service:

#!/usr/bin/env python3
import socket
import sys

def test_resolution(host, port_or_service):
    print(f"[*] Testing resolution for host: '{host}', service: '{port_or_service}'")
    try:
        # Convert port to integer if numeric
        service = int(port_or_service) if port_or_service.isdigit() else port_or_service
        
        # Invoke POSIX getaddrinfo()
        addr_info = socket.getaddrinfo(
            host,
            service,
            family=socket.AF_UNSPEC,     # Allow IPv4 (AF_INET) and IPv6 (AF_INET6)
            type=socket.SOCK_STREAM      # TCP connection
        )
        print(f"[+] Successfully resolved {len(addr_info)} address candidate(s):")
        for idx, (family, socktype, proto, canonname, sockaddr) in enumerate(addr_info):
            family_str = "IPv4" if family == socket.AF_INET else "IPv6"
            print(f"    [{idx + 1}] Family: {family_str:<4} | IP: {sockaddr[0]} | Port: {sockaddr[1]}")
    except socket.gaierror as e:
        print(f"[-] getaddrinfo FAILED: errno={e.errno} -> {e.strerror}")
        sys.exit(1)

if __name__ == "__main__":
    target_host = sys.argv[1] if len(sys.argv) > 1 else "example.com"
    target_service = sys.argv[2] if len(sys.argv) > 2 else "443"
    test_resolution(target_host, target_service)

5. Kubernetes & Docker DNS Resolution Issues

In containerized environments, DNS resolution failures have distinct architectural causes.

                  KUBERNETES ndots:5 QUERY AMPLIFICATION

  Application in Pod queries "api.stripe.com" (Contains 2 dots: < 5 ndots)
                            │
  Kubelet Appends Search Domains Sequentially:
  ├── 1. api.stripe.com.default.svc.cluster.local.     ──► NXDOMAIN (CoreDNS)
  ├── 2. api.stripe.com.svc.cluster.local.             ──► NXDOMAIN (CoreDNS)
  ├── 3. api.stripe.com.cluster.local.                 ──► NXDOMAIN (CoreDNS)
  ├── 4. api.stripe.com.us-east-1.compute.internal.    ──► NXDOMAIN (VPC DNS)
  └── 5. api.stripe.com. (Absolute FQDN query)         ──► SUCCESS (200ms delay!)

1. The Kubernetes ndots:5 Latency & Exhaustion Trap

By default, Kubernetes configures /etc/resolv.conf inside pods with options ndots:5.

  • Any domain with fewer than 5 dots (e.g. api.example.com has 2 dots) will search through all cluster search domains before attempting a direct external query.
  • This results in 4 failed NXDOMAIN queries to CoreDNS for every 1 successful lookup, frequently exhausting CoreDNS CPU and triggering random EAI_AGAIN / nodename nor servname provided timeouts.

The Fix: Use trailing dots for external domains (e.g. api.example.com.) or tune pod dnsConfig:

spec:
  dnsConfig:
    options:
      - name: ndots
        value: "2"

2. Docker Embedded DNS (127.0.0.11) Stalls

In Docker user-defined bridge networks, Docker runs an embedded DNS server at 127.0.0.11.

  • If the host machine changes network interfaces (e.g. connecting to or disconnecting from an OpenVPN/WireGuard tunnel), Docker's embedded DNS server continues forwarding queries to the previous, dead upstream resolver.
  • Fix: Restart the Docker daemon (sudo systemctl restart docker) or specify explicit fallback DNS flags:
    docker run --dns 1.1.1.1 --dns 8.8.8.8 my-app
    

6. IPv4 vs IPv6: The Broken AAAA Record Trap

A frequent cause of intermittent resolution and connection timeouts is asymmetric IPv6 configuration:

  1. An external service publishes both A (IPv4) and AAAA (IPv6) records.
  2. getaddrinfo() returns both addresses, ordering IPv6 first (RFC 6724 address selection).
  3. The local client attempts to connect to the IPv6 address.
  4. However, the host's ISP or cloud network has an unrouted or firewalled IPv6 gateway.
  5. The connection hangs until the TCP connection timeout expires before falling back to IPv4 (or fails completely if the client runtime does not implement RFC 8305 Happy Eyeballs).
# Test if IPv6 resolution is the specific point of failure
dig api.example.com AAAA +short
curl -6 -v --connect-timeout 3 https://api.example.com/ || echo "IPv6 Routing Failed"

7. Troubleshooting /etc/services & Servname Failures

If the error stems from the servname component, the port argument passed to the socket is invalid:

# Inspect registered service names in /etc/services
grep -E '^(http|https|postgres|ssh|redis)[[:space:]]' /etc/services
http              80/tcp        www
https            443/tcp
ssh               22/tcp
postgresql      5432/tcp

Common Servname Mistakes:

  • Passing "http//" instead of "http" or "80".
  • Passing "5432/tcp" instead of 5432.
  • In stripped container base images (e.g. Alpine scratch or minimal distroless images), /etc/services may be completely absent. Passing named services like "https" fails with EAI_SERVICE. Always use numeric port integers (443) in automated production systems.

8. SRE Severity & Resolution Decision Tree

                 SRE RESOLUTION DECISION TREE

  "Could not resolve hostname / nodename nor servname"
                            │
                            ▼
  Does "dig @1.1.1.1 <host>" return valid IP?
  ├── NO  ──► Domain expired, typo in URL, or authoritative DNS down.
  │           (Check domain registrar, WHOIS, and zone records)
  │
  └── YES
       │
       ▼
  Does "getent hosts <host>" work on the host?
  ├── NO  ──► Local OS resolver misconfigured.
  │           (Inspect /etc/resolv.conf, systemd-resolved, or VPN split-DNS)
  │
  └── YES
       │
       ▼
  Is the error occurring inside a Container / Kubernetes Pod?
  ├── YES ──► CoreDNS saturation, search domain loop, or ndots amplification.
  │           (Check CoreDNS logs, pod ndots, and Docker 127.0.0.11)
  │
  └── NO  ──► Application syntax error: URI scheme embedded in host string,
              or hidden CRLF (
) line ending in environment variables.

9. SRE Production Checklist for DNS Reliability

  • Input Sanitization: Application connection strings strictly parse hostnames independently from URL schemes (https://), ports (:443), and paths (/v1).
  • Numeric Ports in Production: Use integer port values (443, 5432) rather than named string protocols (https, postgresql) to avoid /etc/services dependencies.
  • Kubernetes ndots Optimization: High-throughput pods targeting external APIs use ndots:2 or fully qualified domain names with trailing dots (api.stripe.com.).
  • Redundant Upstream Resolvers: /etc/resolv.conf declares at least two diverse Anycast nameservers (1.1.1.1, 8.8.8.8).
  • IPv6 Happy Eyeballs Validation: Verify that dual-stack hosts have functional IPv6 default gateways or configure runtimes to prefer IPv4 if IPv6 egress is disabled.

Conclusion & Next Steps

The error nodename nor servname provided, or not known is not a mysterious kernel fault—it is the direct output of POSIX getaddrinfo() failing to map a hostname or service string to an actionable IP socket.

By verifying hostname inputs, isolating local OS resolvers from public recursive lookup paths, tuning container search domains, and standardizing on numeric ports, you can eliminate name resolution errors across your distributed architecture.


Audit and Test Live DNS Resolution with Pingzoapp

Don't wait for application crashes to find out your external dependencies, domain records, or nameservers are failing.

With Pingzoapp, you get:

  • Global Multi-Region DNS Probing: Monitor DNS lookup latencies, A/AAAA record changes, and nameserver health across multiple continents.
  • Interactive DNS Diagnostic Tools: Test and debug records in real time using our free DNS Lookup Tool.
  • Instant Multi-Channel Alerts: Get notified via WhatsApp, Telegram, SMS, Slack, and Discord the second an endpoint fails name resolution.

👉 Start Monitoring DNS Free with Pingzoapp and safeguard your infrastructure against silent resolution outages.

Zero-Code Uptime Alerts

Stop Finding Out About Outages from Angry Users

Get instant WhatsApp & Discord alerts the second your API, website, or server goes down. Setup in 30 seconds with 60-second checks.

WhatsApp & Discord 60-Second Checks Free Forever Plan
Try Pingzo Free

Know before your users do

Connect official WhatsApp notification channels, Discord webhooks, Telegram bots, and public status pages. Start in 30 seconds.

Create Free Monitor