Skip to content

Understanding Your Diagnosis

heymaikol edited this page Aug 18, 2026 · 3 revisions

Understanding Your Diagnosis

You ran netdoc, you have rows and a summary. This page turns that into a next action.

The single most useful field is the verdict, the summary expressed as one machine-readable word. It answers the question a person on a call-out actually asks: is my network broken, or is theirs?

The six verdicts

Verdict Meaning Whose problem
ok Every check passed. Nobody's
degraded Everything you asked for works, but some rung is impaired. Usually nobody's, yet
dns The name did not resolve. Resolver / config
network The path is unavailable: link down, no egress, or the target unreachable with nothing else proving the network usable. Yours (or the path)
service The path works, the far end does not. Theirs
incomplete A check has no result; the chain did not finish. Neither, so rerun

In a --json run this is the verdict field, beside the human summary. In the TUI it is the sentence under the rows.

The network / service split is decided by evidence, never by guesswork. An unreachable target is blamed on the service only when direct egress independently succeeded, that is, only when there is proof your network works. With no working egress to compare against, the verdict is network, because accusing a host you never reached would be a guess.


ok: everything passed

Nothing to do. If you are still seeing a problem, the fault is above the layers Network Doctor probes: application configuration, authentication, a specific URL path, or something inside the service. netdoc proved you can reach it and complete a handshake; it does not log in for you.

Two things worth trying before you conclude that:

  • Give it the real target. netdoc example.com checks port 443; if your app talks to example.com:8443, check that.
  • Run --watch for a few minutes. An intermittent fault is invisible in a single green pass.

degraded: it works, but something is impaired

This is the verdict people most often ignore and should not. It means the diagnosis found nothing broken for what you asked for, but there is a real finding sitting beside it. Look for the ! rows.

Common shapes, and what each actually means:

"Online via the environment proxy: direct egress is blocked (proxy-only network)." Your machine has no direct route out; the configured HTTPS_PROXY/ALL_PROXY does. This is normal on many corporate networks. The action is to make sure the tool that is failing actually honours the proxy environment variables; many do not.

"…the configured environment proxy check failed, so apps that use the proxy will fail…" The mirror image. Direct egress is fine, but your proxy configuration is broken. Anything that respects HTTPS_PROXY will fail while curl --noproxy '*' works. Check the proxy variables for a stale host, a dead port, or a NO_PROXY that no longer covers what it should.

"…the QUIC handshake over UDP/443 failed. Applications can fall back to TCP, which may feel slower." TCP/443 works, UDP/443 does not. Something on the path filters QUIC. Browsers fall back to TCP automatically, so the symptom is slow page starts rather than an outage. Worth reporting to whoever runs the firewall; not worth an incident.

Encrypted DNS unavailable while plaintext DNS works. Ordinary port-53 DNS resolves, but neither DoH nor DoT completed a verified exchange. This is the shape of "my terminal resolves fine but my browser cannot", because modern browsers try encrypted DNS first. The probes can show that one transport worked and the other did not, but not that anybody intended it, so Network Doctor deliberately says no more than this:

"The resolver may be unavailable, or the network may be blocking or interfering with DoH/DoT."

"…system DNS and public DNS disagree; split DNS or filtering may be intentional…" Your resolver and the public second opinion returned different addresses. On a VPN or a corporate network this is usually correct and deliberate (split-horizon DNS). It is reported as a Warn precisely because it is not automatically wrong. It becomes interesting when you did not expect it.

High latency, or one address family down. internet_tcp reports IPv4 and IPv6 independently, in parallel. ipv6_unreachable with IPv4 fine is extremely common and usually harmless; it becomes the answer when the thing you are debugging is IPv6-only.


dns: the name did not resolve

Look at which DNS rows failed, because they point at different fixes.

What you see What it means What to do
System DNS fails, public DNS resolves the name Your configured resolver is failing or filtering. Check /etc/resolv.conf, your VPN's pushed resolver, a DNS filter or ad-blocker, or a stub resolver that has stopped.
Both report no A/AAAA records The name genuinely has no records. Check the spelling; check whether the record was actually published.
System DNS fails, public DNS unreachable too Often not really a DNS problem. Look at the egress rows first, because if there is no egress, DNS failing is a symptom, not the cause.

That last row is why the verdict logic checks egress before blaming DNS: without working egress, a DNS failure is downstream of the outage.

Drill down with d (dig on Linux/macOS, nslookup on Windows) to see what the resolver actually said.


network: the path is unavailable

Something between you and the target is not carrying traffic. Work down the branches, because they narrow it fast.

Is the interface up? If the Interface row failed, stop here. Nothing else means anything.

Are you behind a captive portal? This is checked first, ahead of everything else, and for good reason: behind a portal every layer below is answering for the portal, so nothing further down the stack means what it says. The summary says so before it says anything else:

"Behind a captive portal: traffic is intercepted until you sign in to the network."

Sign in first and rerun. The row includes the sign-in URL when the response supplied a valid one (the app displays it but never opens it).

Is direct egress dead but the proxy alive? Then it is a proxy-only network; see degraded above.

Is nothing reachable at all? The summary is:

"…neither it nor the general internet is reachable: local egress problem."

Look at your default route (i in the toolbox), your gateway, and your Wi-Fi association.

Does TCP connect and then everything stalls? Check the Path MTU row. If it warns that a 24 KiB write went unacknowledged and a protocol check timed out, the verdict names a probable MTU black hole. This is the tunnel/VPN/PPPoE fault described in How Network Doctor Works. The fix is almost always to lower the MSS or MTU on the tunnel interface, and the row suggests the experiment.

On Linux, a failed direct-egress row may carry a structured cause that names the kernel-level reason: no_default_route, gateway_unreachable, selected_path_failed, or preferred_route_failed. Those are visible in --json under cause.


service: the path works, the far end does not

This is the verdict that lets you stop debugging your own machine. The general internet was independently proven reachable, and this specific target still is not working.

Row that failed What it means Likely cause
TCP DNS resolved and the internet works, but the port does not answer. Remote port closed, remote firewall, or VPN routing that does not cover this destination.
TLS TCP connects, the handshake does not. Expired or not-yet-valid certificate, hostname mismatch, untrusted issuer, clock skew, or a MITM proxy.
HTTPS TLS is fine, no HTTP response. Application-layer block, or a proxy sitting in front.
HTTP (on a TLS target) HTTPS works but the plain :80 endpoint does not. The redirect endpoint is blocked or not served. Often harmless.
SSH / SMTP banner TCP is accepted, the banner check failed. Service not actually running on that port, or refusing before it speaks.

A Warn on a banner row is not a failure:

"…accepts TCP but sent no service banner."

Some services legitimately wait for the client to speak first.

For TLS specifically, --json gives you a stable cause so you do not have to parse prose: certificate_expired, certificate_not_yet_valid, hostname_mismatch, untrusted_issuer, tls_handshake_failure, tcp_unreachable, timeout, connection_closed. The full list of causes across every probe is in the README's JSON output section.


incomplete: the chain did not finish

A probe has no result. You quit before it finished, or the run was interrupted. Rerun it. If it happens repeatedly, that is worth an issue; include a --json run.


Worked example: telling the two important cases apart

Both of these are "I cannot reach the service." They have opposite fixes.

Case A

✓ Interface            using wlan0 …
✓ Internet (TCP egress)
✓ DNS api.example.com  → 203.0.113.10
✗ TCP api.example.com:443

Direct egress passed. So the network demonstrably works, and this one host does not answer. Verdict: service, from:

"…is unreachable though DNS and the general internet work: remote port closed, firewall, or VPN routing."

Stop debugging your laptop; go ask whoever runs the service, or check whether your VPN covers that subnet.

Case B

✓ Interface            using wlan0 …
✗ Internet (TCP egress)
✓ DNS api.example.com  → 203.0.113.10
✗ TCP api.example.com:443

Egress failed too. The name resolved (a cached or local answer will do that), but nothing is reachable. Verdict: network, from:

"…resolves but neither it nor the general internet is reachable: local egress problem."

Network Doctor deliberately does not say the service is down, because it never got far enough to know.

The only difference between the two is one independent row. That is the whole reason the egress branch does not depend on DNS.


Getting proof

A verdict is a conclusion; the drill-down tools give you the artefact. Press the hotkey for the tool you would have reached for anyway: t for traceroute, c for curl (or a protocol-appropriate handshake probe on SSH/SMTP targets), m for mtr/pathping, i for the route table, s for sockets. Jobs stream, run concurrently, and tab switches between them.

y / w copy or save a reviewable report of the whole chain plus every tool job.

Review it before sharing. Tool evidence may contain internal hostnames, addresses, usernames, and interface names.

Where next

Clone this wiki locally