fix(server): Windows socket read/write fails with GetLastError(87)#21
Open
TheRefreshCNFT wants to merge 5 commits intonullclaw:mainfrom
Open
fix(server): Windows socket read/write fails with GetLastError(87)#21TheRefreshCNFT wants to merge 5 commits intonullclaw:mainfrom
TheRefreshCNFT wants to merge 5 commits intonullclaw:mainfrom
Conversation
…WriteFile Zig 0.15.2's std.net.Stream.read/write uses ReadFile (via NtReadFile) on Windows, which fails on sockets with GetLastError(87) 'The parameter is incorrect'. This is the same class of bug fixed in nullclaw PR #550. Adds net_compat.zig with Windows-safe socket I/O that uses ws2_32.recv and ws2_32.send directly, falling back to std stream operations on other platforms. All socket read/write paths in server.zig now go through the compat layer.
On Windows, resolving nullhub.localhost blocks until the 350ms timeout fires, causing a blank screen on load. The UI only renders after DevTools is opened (which adds enough latency to let the timeout complete). Fix: bail out early if already on the direct fallback host (127.0.0.1), skipping the DNS probe entirely. The redirect is only needed when arriving via a hostname alias.
CSS @import url() is render-blocking — the browser won't paint anything until the external stylesheet finishes loading. On slow connections or when Google Fonts stalls, this causes a black screen that only resolves when DevTools is opened (triggering a repaint). Move font loading to async <link> tags in app.html using the media=print/onload=all pattern, with a noscript fallback.
… expansion - paths.zig: append .exe suffix on Windows for binary path resolution - supervisor/health.zig: use ws2_32 compat layer (net_compat.zig) for health check socket I/O, same fix as server.zig (NtReadFile fails on sockets) - launch_args.zig: expand bare 'channel' launch_mode to 'channel start' so Hub can supervise nullclaw channel mode; adds test coverage
Only 'serve' mode exposes an HTTP health endpoint. All other modes (agent, gateway, channel, or any future long-lived non-HTTP mode) should be supervised by process-alive checks only (port=0). Previously only 'agent' was exempted, meaning gateway/channel modes would incorrectly attempt HTTP health probes and fail.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Windows compatibility fixes
Five fixes that get NullHub running correctly on Windows 10/11 with Zig 0.15.2.
1. Server socket I/O — ws2_32 recv/send (
server.zig,net_compat.zig)Problem: NullHub's HTTP server crashes immediately on Windows:
error.Unexpected: GetLastError(87): The parameter is incorrect.
std.os.windows.zig:648:53 in ReadFile
std.net.zig:2325:36 in read
server.zig:339:35 in handleConnection
Zig 0.15.2's
std.net.Stream.read/writeusesNtReadFile/NtWriteFileinternally, which fail on sockets — Windows requiresws2_32.recv/ws2_32.sendfor socket I/O.Fix: Adds
net_compat.zigwith a thin platform-aware compat layer (streamRead,streamWrite,streamWriteAll). All socket paths inserver.ziggo through it. No-op on non-Windows. Same class of fix as nullclaw/nullclaw#550.2. Health check socket I/O — same compat layer (
supervisor/health.zig)Problem: The supervisor health probe has the same
NtReadFileissue —stream.read/writeAllinhealth.zigalso crash on Windows sockets.Fix: Health check now uses
net_compat.streamReadandnet_compat.streamWriteAll, consistent with the server fix.3. Binary path missing
.exeon Windows (core/paths.zig)Problem:
Paths.binary()constructs paths like~/.nullhub/bin/nullclaw-standalone— without the.exesuffix, the binary is never found on Windows and the instance fails to start.Fix: Appends
.exeonbuiltin.os.tag == .windows, no change on other platforms.4.
channellaunch mode expands tochannel start(core/launch_args.zig)Problem: When an instance is configured with
launch_mode: "channel", Hub passesnullclaw channelto the process — which prints usage and exits. The runnable command isnullclaw channel start.Fix:
buildLaunchArgsdetects a barechanneltoken and appendsstart, making the mode actually supervisable. Includes test coverage.5. Skip HTTP health checks for non-server launch modes (
api/instances.zig)Problem: Only
agentmode was exempted from HTTP health probes. Modes likegatewayandchannelexpose WebSocket/gateway traffic — not an HTTP health endpoint — so health probes would always fail, causing the supervisor to repeatedly mark instances as unhealthy.Fix: Flips the logic: only
servemode gets HTTP health checks. All other modes (agent,gateway,channel, or any future non-HTTP mode) are supervised by process-alive checks only (port=0). No component names hardcoded.Testing
Built and tested on Windows 10 x64, Zig 0.15.2:
/health→{"status":"ok"}/api/instances→ valid JSONGetLastError(87)crashesRelated: nullclaw/nullclaw#317, nullclaw/nullclaw#550