Repository navigation
Fix Windows sidecar install extension mismatch, redirect GUI stdio to log files - #2614
Merged
Merged
Conversation
… log files (closes #2137) Real-Windows validation of PR #2136/#2140's daemon stderr-to-file fix surfaced a genuine bug: extract_sidecar_if_changed installed the daemon binary under ~/.nodespace/bin/ using the bare daemon_binary_name() ("nodespaced"), never routed through bundled_sidecar_name(), so the extracted file carried no .exe extension. The daemon still spawned (a literal existing path resolves via Command::new even without an extension), but registered in the Windows process table under the bare image name, so kill_running_daemon's taskkill /IM nodespaced.exe never matched it -- confirmed live on a Windows box: taskkill reported "process not found" while the real process kept running, for both community and Pro edition names. A restart could therefore never kill the previous daemon before spawning a new one. Fix: route both the install destination (extract_sidecar_if_changed) and the launch/kill path (ensure_daemon_running's daemon_bin) through a single new sidecar_install_path() helper, so they can't drift apart again. Everything else in the daemon stderr-to-file path -- log file creation/append, handle inheritance into a DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP child, append-not-truncate across a simulated restart, and the real SchemaNode::from_node fields-parse diagnostic landing in nodespaced-error.log -- verified working as-is on the same Windows box. Separately, add a fix for the GUI process's own console-less stderr (schemas.rs's two direct SchemaNode::from_node calls, discarded by windows_subsystem = "windows" in release builds): redirect this process's own STD_OUTPUT_HANDLE/STD_ERROR_HANDLE to log files via SetStdHandle at startup, gated to release-on-Windows so debug builds keep their attached console. Verified on a real Windows box with a standalone windows_subsystem = "windows" harness launched with no inherited stdio: eprintln!/println! output is lost before the redirect and lands correctly in the log file after it, including the real SchemaNode::from_node diagnostic on a genuinely malformed schema. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6 tasks
malibio
added a commit
that referenced
this pull request
Sep 27, 2026
The doc comment claimed the eprintln! diagnostic is invisible on Windows/release builds since those have no console, but PR #2614 already redirects the Windows daemon and release-GUI stdio to persistent log files, closing that gap. Update the comment to reflect that the diagnostic is universally log-file-only rather than two-platform-specific. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.
Closes #2137
Summary
Live-validated PR #2136/#2140's daemon-side stderr-to-file fix on a real Windows box (SSH access to a Windows 11 machine, real MSVC toolchain, no libclang/LLVM so no full
nodespaced/nodespace-appbinary build — verification below uses the same standalone-harness technique used for #1452/#1498/#1519). Investigation surfaced a real, previously-unconfirmed bug in the sidecar install path, fixed here. Also implements the separate, previously-unaddressed fix for the GUI process's own console-less stderr.Part 1: real Windows validation of PR #2136/#2140, and a real bug found + fixed
The issue's "check this first" item was real.
extract_sidecar_if_changedcomputed its install destination asbin_dir.join(name), wherenameis the bare, cross-platformdaemon_binary_name()/CLI_BINARY_NAMEconstant ("nodespaced", never routed throughbundled_sidecar_name, which is what correctly appends.exeon Windows for the source-lookup half of the same function). So the daemon binary actually extracted to~/.nodespace/bin/on Windows carried no.exeextension — confirmed on a real Windows box,dirshows a file literally namednodespaced, notnodespaced.exe.This is a different, more subtle bug than what the issue speculated (a CI/release-pipeline naming mismatch preventing install entirely — that part is fine:
release.ymlcorrectly producesbinaries/nodespaced-{triple}.exe, and Tauri's bundler correctly stages it asnodespaced.exebeside the app's own.exe, confirmed by the pre-existingsidecar_sits_beside_the_windows_exetest). The bug is entirely in this repo's ownextract_sidecar_if_changed, so it's fixed directly here rather than filed as a separate CI-pipeline issue.Real-Windows evidence (standalone harness: vendored
nodespace-types— confirmed dependency-light, no DB/HTTP/NLP deps, builds natively on the Windows box — plus faithful re-implementations ofdaemon_setup.rs's Windows functions,[[bin]]targetsextractor/spawner/killer/fakedaemon):Control (fixed extension) isolates the root cause — same taskkill command now matches correctly:
Same result for the Pro edition name (
nodespaced-provsnodespaced-pro.exe).Practical impact of the bug (unfixed): the daemon still starts fine on first install (
Command::newresolves an extensionless full path that literally exists), but a binary-update restart'skill_running_daemonsilently fails to kill the previous instance (thetaskkillcall's result is ignored —let _ = ...output()), so the old daemon keeps holding the named pipe while a new one is spawned alongside it.Fix: new
sidecar_install_path(bin_dir, name)helper (routes through the existingbundled_sidecar_name), used as the single source of truth by bothextract_sidecar_if_changed's install destination andensure_daemon_running'sdaemon_bin— the exact two places that had silently drifted apart. Two new unit tests pin this (sidecar_install_path_carries_the_native_extension,sidecar_install_path_covers_pro_daemon_and_cli_names).Rest of the Part-1 checklist — verified working as-is, no code changes needed:
spawn_daemon_windowscreates/appendsnodespaced.log/nodespaced-error.logunder~/.nodespace/logs/— confirmed.OpenOptions::create(true).append(true)-opened file handles correctly inherit into aDETACHED_PROCESS | CREATE_NEW_PROCESS_GROUPchild spawned viaStdio::from(File)— confirmed real: the child's stdout/stderr both land in the log files.fieldsvalue (a string, not an array) fed through the realnodespace_types::SchemaNode::from_node/parse_fieldsproduces the exactnodespace-types: SchemaNode::from_node: failed to parse fields for schema node ...diagnostic, and it lands correctly innodespaced-error.log.Part 2: fix the GUI process's own console-less stderr
commands/schemas.rs'sget_all_schemas/get_schema_definitioncallSchemaNode::from_nodedirectly inside the Tauri GUI process, which builds withwindows_subsystem = "windows"in release (main.rs) — no console at all, so PR #2136's daemon-side fix (child-processStdioredirection) doesn't touch this at all.Approach chosen:
SetStdHandle(STD_ERROR_HANDLE/STD_OUTPUT_HANDLE, <log file handle>)at GUI process startup, inmain.rs, gated to release-on-Windows (debug builds keep their attached console). Reconsidered the other candidate (restructuringSchemaNode::from_nodeto return the diagnostic viaResult) and kept the original #2128 rationale for rejecting it: it has three production call sites, two of them here and one (node_to_typed_value, vianodes_to_typed_values's batchResultcollection) reachable from every non-GUI entry point (CLI, MCP, HTTP) — none of which have this bug. Threading the diagnostic through the sharednodespace-typesAPI to fix a two-call-site, GUI-process-local problem would be a much larger blast radius than a self-contained fix inmain.rs/daemon_setup.rs. Nothing about having real Windows access now changes that trade-off.Real-Windows proof it actually works (this was the genuinely uncertain part: does
SetStdHandleactually affect Rust's ownio::stdout()/io::stderr()/eprintln!machinery, or does Rust cache a "no console" state from before the call?). Standalone#![windows_subsystem = "windows"]harness with the fix's exact function bodies, launched viacmd /c start /WAIT(genuinely no inherited stdio — a direct SSH invocation instead inherits sshd's own piped stdio and doesn't reproduce the bug):The harness's
BEFORE-REDIRECTlines never appear anywhere (confirmed lost, matching the real bug); theAFTER-REDIRECTlines and the realSchemaNode::from_nodediagnostic both land correctly in the log files — confirming Rust's stdio machinery re-resolves the OS standard handle at write time rather than caching a stale state, on this Rust/Windows version.Verification gap, stated honestly
The full
nodespace-appcrate (andnodespaced) still cannot be built or run on this Windows box — it depends transitively onnodespace-nlp-engine/llama-cpp-sys-2, which needs libclang/LLVM (installing it was explicitly blocked by this session's safety classifier; no other software install was attempted). Every real-Windows claim above is therefore from a standalone harness that either vendors the actual lightweight crate (nodespace-types) or faithfully re-implements the specificdaemon_setup.rs/main.rsfunctions being tested — not a build of the realnodespace-app/nodespacedbinaries themselves.cargo check -p nodespace-app --bins --liband the fullbun run test:all(unit + browser + Rust, including the Tauri-seam ADR-048 integration tests) pass on macOS.Testing
bun run test:all— clean (4955+ frontend tests, 167 desktop-app Rust unit tests including 2 new regression tests, full Tauri-seam integration suite).bun run quality:fix— clean, no additional changes beyond the two files above.cargo check -p nodespace-app --bins --lib— clean on macOS.🤖 Generated with Claude Code