{"record":{"id":"da21dd775f4b8814","repo":"vitessio/vitess","slug":"connection-dns-for-s-has-changed-old-v-new","errorCode":null,"errorMessage":"Connection DNS for %s has changed; old: %v  new: %v","messagePattern":"Connection DNS for (.+?) has changed; old: (.+?)  new: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"info","filePath":"go/netutil/netutil.go","lineNumber":150,"sourceCode":"\tif dnsName != \"\" {\n\t\taddrs, _ = dnsLookup(dnsName)\n\t}\n\n\treturn func() (bool, error) {\n\t\tif dnsName == \"\" {\n\t\t\treturn false, nil\n\t\t}\n\t\tnewaddrs, err := dnsLookup(dnsName)\n\t\tif err != nil {\n\t\t\treturn false, err\n\t\t}\n\t\tif len(newaddrs) == 0 { // Should not happen, but just in case\n\t\t\treturn false, fmt.Errorf(\"Connection DNS for %s reporting as empty, ignoring\", dnsName)\n\t\t}\n\t\tif !addrEqual(addrs, newaddrs) {\n\t\t\toldaddr := addrs\n\t\t\taddrs = newaddrs // Update the closure variable\n\t\t\treturn true, fmt.Errorf(\"Connection DNS for %s has changed; old: %v  new: %v\", dnsName, oldaddr, newaddrs)\n\t\t}\n\t\treturn false, nil\n\t}\n}\n\nfunc addrEqual(a, b []net.IP) bool {\n\tif len(a) != len(b) {\n\t\treturn false\n\t}\n\tfor idx, v := range a {\n\t\tif !net.IP.Equal(v, b[idx]) {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}\n\n// NormalizeIP normalizes loopback addresses to avoid spurious errors when","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/netutil/netutil.go#L132-L168","documentation":"DNSTracker detects that the IPs behind a tracked hostname have changed since the connection was created and returns this error to signal the caller that the connection must be re-established. It is an intentional signal, not a malfunction: DNS rebalancing or failover changed the target addresses.","triggerScenarios":"checkAndRefreshDNS finds addrEqual(addrs, newaddrs) false — e.g. a tablet was rescheduled (new pod IP), a DNS record was updated for failover, or a load-balancer endpoint changed — during a DNSTracker refresh of an existing connection.","commonSituations":"Kubernetes pod restarts getting new IPs; DNS-based failover switching to a standby; TTL expiry after record changes; rolling updates changing service endpoint IPs.","solutions":["Treat the returned error as expected: close and recreate the connection to the new address (the tracker's purpose is to trigger this)","Ensure callers honor the (true, err) return and retry the dial; don't suppress it","Increase DNS TTL stability or pin records if changes are unintentional","Check why the record changed (failover vs. misconfigured DNS automation)"],"exampleFix":"// before (ignoring refresh signal)\nchanged, _ := tracker.Check(); _ = changed\n// after\nchanged, err := tracker.Check()\nif changed || err != nil {\n    conn.Close()\n    conn = dial(addr) // reconnect to new IPs\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"changed, err := tracker.Check()\nif changed {\n    conn.Close()\n    conn, err = dial(addr) // DNS changed: reconnect to new IPs\n    if err != nil {\n        return retry.Do(func() error { conn, err = dial(addr); return err })\n    }\n}","preventionTips":["Always honor the (true, error) return from DNSTracker checks by reconnecting","Use stable DNS records / reasonable TTLs to reduce churn","Expect this during pod reschedules and failovers; make reconnect logic idempotent"],"tags":["network","dns","reconnect","address-change"],"backgroundTag":"dns-record-changed","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}