guides · how-to
Troubleshooting
Find your symptom, get the cause. Organised by what you are actually seeing rather than by which component is at fault.
Start with the symptom you can see. Most of these have one likely cause and a fast way to confirm it.
Two things are worth checking before anything else, because they explain a surprising share of problems:
- The host’s tray icon. Grey means idle — the host has seen no client at all. Green means a client is connected. Red means an error. If you’re debugging a connection failure and the tray is grey, the problem is between the client and the host, not inside the host’s settings.
- The version line at the top of
C:\ProgramData\NearZero\logs\host.<date>.log:
nearzero-host listening version="0.9.x (3eb3a7f)" protocol=3 listen=0.0.0.0:48010 ...
What must match between host and client is the line: the leftmost non-zero number, 0.9 here. The rest of the number need not match, and usually will not. Hosts and clients on the same line connect and pair; on different lines the handshake fails cleanly and says so, rather than misbehaving later. If connecting or pairing stopped working right after you updated one machine, the two are probably on different lines now: update the one that is behind. See which versions work together.
Connection
The client can’t reach the host at all
The tray icon stays grey, and the client times out or refuses immediately.
The host never saw the connection, so look at the path rather than the host’s configuration. Which path that is depends on your setup:
- With a rendezvous configured, the client goes through it first — the rendezvous names each host by its identity, so several hosts on one network (all on the default port) can never be confused with each other. So check the rendezvous leg before anything else: is the server up, and is this host enrolled and connected to it? A recorded direct address is only tried as a fallback when the rendezvous leg fails.
- Without a rendezvous, the recorded address is the whole story. Is it right? The host listens on UDP 48010 by default — confirm what it actually bound to from the
listen=field in the log line above. - Is UDP 48010 allowed through? The installer adds a firewall rule, but a third-party firewall or a VPN client may not honour it.
- Reaching it from outside your network? That needs a rendezvous, or a port forwarded directly to the host.
It connects, then immediately fails at the handshake
Two causes, and the error text now tells them apart:
- “a machine answered at the recorded address but it is not the pinned host” — something reached QUIC, but the cryptographic handshake proves it isn’t the host you paired. With every host defaulting to port 48010, a recorded address can quietly come to mean a different machine (DHCP reshuffle, repointed port-forward). If a rendezvous is configured this can only happen on the fallback path — fix the rendezvous leg and the address stops mattering. Otherwise, correct the address. (It can also mean the host’s identity was rotated — then re-pair.)
- The two ends are on different lines — a 0.9 host and a 0.10 client, say. They refuse each other by design, and the handshake fails cleanly. Compare the version in the host log with the client’s About screen, and update whichever is on the older line.
“Incorrect password — please try again.”
The connection password, which is separate from the admin password.
Be aware of the throttle: 5 wrong attempts in a row is a 1-minute ban, and 10 within ten minutes is a 10-minute ban. If you’re now getting failures that look different from a wrong password, you may simply be banned — wait it out rather than retrying harder.
If a reconnect fails where the first connect worked, the client may have no cached password for the reconnect; disconnect fully and connect again so it prompts.
The client is refused even though it used to work
If the host’s identity was rotated, or its config directory was wiped or moved, every pin is gone and the client is refused at the Noise gate. Clients that aren’t in Known clients are refused before they can say anything about themselves.
You’ll need to pair again. Note the reverse is not a cause: simply changing networks never requires re-pairing, because the pin is on the host’s identity rather than its address.
Pairing
Pairing from outside the network times out with no error
This is the most common setup mistake, and the failure mode gives you nothing to go on.
A pairing token embeds how to reach the host at the moment it was minted. Mint one before enrolling the rendezvous bundle into the host, and the token carries no way to reach you from elsewhere — so the client sits there until it gives up.
The fix is ordering, not settings:
- Deploy the rendezvous and give it a public address.
- Print its bundle and paste it into the host’s Settings → Rendezvous.
- Wait about a minute for the host to reconnect.
- Mint a fresh token.
Existing tokens do not gain the rendezvous retroactively. The host’s Pairing page warns you about both variants of this — “No rendezvous is enrolled” and “Your rendezvous is enrolled under a private address” — and it’s worth reading rather than clicking past.
Pairing is refused because of a version mismatch
Hosts and clients on the same line always pair, whatever the rest of their numbers say. If pairing is refused over a version, the two are on different lines. Compare the version line in the host log with the client’s About screen, and update whichever is on the older line. If the client says the host is too old, that is the host.
The PIN is rejected
The PIN is never sent or compared as a message; each side proves inside the handshake that it knows it — so a wrong one fails cryptographically, on both ends, rather than producing a “wrong PIN” reply. Approve within 60 seconds; after that, mint a new one.
If you’re redeeming a token rather than a PIN, an expired or already-redeemed token is deliberately indistinguishable from a wrong code. Generate a fresh one.
Picture and sound
Black screen, but the session says it’s connected
A black screen with an active session most often means curtain mode is on, or the selected display is genuinely blank.
If neither applies and the session is otherwise healthy, the video layer may have been dropped by the compositor. Press Ctrl + Alt + Shift + R — a beta-only diagnostic that forces it to re-attach. Whether or not the picture returns is itself the useful information, so please report which happened; see tips and tricks for why.
Quality is worse than expected
Check the statistics overlay first (Ctrl + Alt + Shift + S); the causes want opposite fixes.
- Bitrate well below what you requested — the host clamped it. The client can only ask; the ceiling is Settings → Encoder → max bitrate.
- You’re on the extended canvas — every attached monitor composited into one image means your bitrate is spread across all of it. Switch to a single display with
Ctrl + Alt + Shift + 1…9. - Brief smearing after a stall — packet loss, normal on Wi-Fi. Recovery is a single flagged frame rather than a full keyframe, so it should clear within a frame or two rather than persisting.
The host’s GPU shows 50–100% “3D” usage while streaming
Almost always enable_aq on the host’s Encoder page. Turn it off and the graph drops to zero; that is the whole fix.
What you’re seeing is accounting rather than work. Adaptive quantization’s per-frame analysis runs as 3D-engine work, and Windows bills the time that context is resident rather than the time it is executing. On a measured 1080p60 session the graph read 86% with it on and under 1% with it off — while real GPU utilisation (3–4%), encoder load (8%), clocks and power draw were identical either way. Your stream is not being slowed down and your GPU is not working hard.
So it’s your choice rather than a fault: keep it on for better quality on detailed scenes, or turn it off so the graph is readable. If the graph is high and enable_aq is already off, that is worth reporting — please include the host log.
No audio
Audio streams what the host is playing, not what a microphone hears — so if the host itself is silent, so is the stream. That’s the first thing to rule out.
- Windows host — check Settings → Audio isn’t set to
none, and that the master toggle is on. Audio comes from the default render device, so if the host’s output device changed, that’s where to look. - macOS host — check Settings → Audio the same way:
enabled,backend,frame_msand the bitrate fields all apply to a Mac host, and switching audio off there means it never opens a capture stream.sample_rateandchannelsare the two that don’t apply — a Mac is fixed at 48 kHz stereo. Also confirm the app has Screen Recording permission, which is what ScreenCaptureKit captures audio under. - Linux host — no audio capture exists, and the client runs video-only by design.
Changes to audio settings only take effect on the next reconnect.
Input
Typing produces the wrong characters
Working as designed. Keys travel as physical positions, and the host’s keyboard layout decides what they produce — a German host types z where a US host types y.
Change the layout on the host. Changing it on the client does nothing.
Input feels stuck, or a modifier is held down
Press Ctrl + Alt + Shift + Z to release mouse and keyboard back to your own machine.
Nothing I type or click reaches the host
You may be a watcher rather than the driver. When several clients share a session, exactly one drives, and the host refuses input from the rest — refuses on the host, not merely greys out buttons.
The client shows which role you hold. If you expected to drive, check Settings → Sessions → allow_takeover on the host.
Multi-client sessions
A client is refused while the host is busy
Two possibilities. With allow_takeover off, a client arriving at a busy host waits rather than taking the wheel. And clients older than multi-viewer support cannot be told they’re read-only, so a busy host refuses them outright rather than admitting them to a session that would silently ignore everything they typed.
To keep a host single-client deliberately, set max_watchers to 0.
Curtain mode is unavailable
Three reasons, in order of likelihood: the host’s allow_curtain policy is off (Settings → Privacy) — the machine’s owner decides, not the remote user; the host is a macOS host, which doesn’t implement it yet and reports so; or the client reports “Host is too old for screen hiding”, meaning the host is a build without it. Update the host; the session works without the feature until then.
Rendezvous
“no endpoints configured”
WARN no endpoints configured — `endpoint set <name> <host:port>`.
The server runs, but `bundle` cannot tell devices where to find it.
Expected on a fresh server. It runs, but can’t tell devices where to find it. See step 2 of the rendezvous guide — and note that how many addresses you need depends on whether the server is on a VPS or on your own network.
Devices can’t find the rendezvous after your IP changed
If you set the public endpoint to a literal IP address and your ISP rotated it, that address is now wrong. Use a dynamic-DNS name instead — devices resolve it at connect time, so it survives the change:
nearzero-rendezvous endpoint set public home.example.duckdns.org:48020
Restart the server afterwards, then re-issue the bundle.
The rendezvous refuses devices at connect
Each host and client line works with exactly one rendezvous line, and the rendezvous checks for an exact match when a device connects. Compare the server’s version (the first line of its log) with your devices’ against the pairs in which versions work together. If you updated hosts and clients across a rendezvous break, move the server to its new line too; the rendezvous guide says how.
The container starts but nothing can reach it
Check UDP 48020 is forwarded to the machine, and the relay range 48030–48069 if you want relay fallback. On rootless Podman, also confirm loginctl enable-linger $USER — without it the service dies when you log out.
Installing
SmartScreen blocks the installer
Beta builds are not code-signed yet. More info → Run anyway. Verify the SHA-256 published beside the download if you want certainty about what you’re running.
The browser warns about the admin UI’s certificate
Expected. The host generates a self-signed certificate on first run, because no certificate authority will issue one for 127.0.0.1. The UI binds to loopback only and is not reachable from your network.
Uninstalling left my configuration behind
By design, unless you asked otherwise — the uninstaller keeps C:\ProgramData\NearZero so a reinstall finds your pairings. Tick “Also delete configuration, pairings and logs” during uninstall for a clean slate.
A silent uninstall (/VERYSILENT) never prompts and always keeps the tree.
Still stuck?
The host log is the best runtime truth available — it records what the host actually negotiated, which is frequently not what the settings pages imply it should have. The last 14 days are kept at C:\ProgramData\NearZero\logs\host.<date>.log, and any account can open them without an administrator prompt — right-click the host’s tray icon → Open logs folder.
When reporting a problem, the log beats a description of it.