“It is always DNS” is a joke because the failures are rarely in DNS itself. They are in which resolver a program asked, and which cache answered.
1. Ask the right question first
dig talks to a nameserver directly. Your application talks to the stub resolver in glibc. They can disagree, and when they do, only the second one matters:
dig +short example.com # asks the server in resolv.conf
getent hosts example.com # asks NSS, the way an application does
resolvectl query example.com # asks systemd-resolved, with its cache
If dig is right and getent is wrong, the problem is in /etc/nsswitch.conf, in /etc/hosts, or in a resolver cache — not on the authoritative server.
2. Follow the delegation yourself
dig +trace example.com
This walks from the root down and shows which nameserver produced the final answer. It is the fastest way to catch a stale delegation, where the parent zone points at a server the child no longer runs.
3. Inspect the cache instead of guessing at TTLs
resolvectl statistics
sudo resolvectl flush-caches
Flush before declaring a change broken, and after declaring it fixed. Half the “propagation” complaints in any incident channel are a local cache holding a record with a TTL somebody set to a day.
4. Watch it live
sudo tcpdump -ni any port 53 -c 20
Twenty packets usually settle the argument about who is asking what. If nothing appears at all, the process is not resolving — it has an address cached, or a proxy is answering, and the whole DNS investigation was aimed at the wrong layer.