Internal/External
External
Area
Other: tracing / stdout output on Windows.
Summary
On Windows, cardano-node writes its stdout trace output in the process's legacy code page instead of UTF-8. Two consequences follow from one cause:
- A non-ASCII character that exists in the code page is written in that code page's byte form, so the JSON lines on stdout are not valid UTF-8. With
TraceOptionNodeName: "talosü", the Reflection.TracerConfigInfo line contains "ApplicationName":"talos\x81". 0x81 is ü in OEM code page 437, the test host's OEM code page; UTF-8 would be C3 BC and CP1252, the host's ANSI code page, would be FC.
- A character that does not exist in the code page makes the stdout writer thread throw, and because that thread is linked to the main thread, the node exits at startup, before it opens its database:
<stdout>: commitAndReleaseBuffer: invalid argument (cannot encode character '\12373').
The host name is the wider path: every trace line carries it, in the "host" field of the JSON format and in the prefix of the human-readable format, and it comes from getHostName independently of TraceOptionNodeName. TraceOptionNodeName itself also defaults to the host name. On a machine whose computer name contains non-ASCII characters, every trace line is therefore affected under the stock configuration. Characters outside the code page (for example a Japanese, Chinese or Korean name on a machine whose code page is 437) stop the node at its first trace line; this was reproduced on 11.1.2 by setting the host name through TRACE_DISPATCHER_LOGGING_HOSTNAME.
The same applies to stderr: when an error message contains a path the code page cannot represent, such as one under a user profile whose name uses characters outside the code page, writing it fails, the encoding error replaces the original exception, and the message is cut off.
Steps to reproduce
- On Windows with an English locale (test host: ANSI code page 1252, OEM code page 437), take a stock preprod
config.yaml and add one key: "TraceOptionNodeName": "talosü". Save the file as UTF-8.
- Start the node with stdout redirected to a file:
cardano-node.exe run --config config.yaml --topology topology.yaml --database-path db --socket-path \\.\pipe\node.socket --port 3001 > out.txt 2> err.txt
- Stop it after a few seconds and inspect
out.txt as bytes. The Reflection.TracerConfigInfo line contains 74 61 6c 6f 73 81 22 (talos, 0x81, "), which is not valid UTF-8.
- Repeat with
"TraceOptionNodeName": "さん" (U+3055 U+3093). The node exits almost immediately and err.txt contains the exception quoted below.
- Control:
"TraceOptionNodeName": "talos-x" runs normally and every stdout line is valid UTF-8.
- Host name path: keep an ASCII
TraceOptionNodeName and set the environment variable TRACE_DISPATCHER_LOGGING_HOSTNAME=Günther (or さん) before starting the node. This sets the same hostname value that the node otherwise takes from the computer name.
The configuration file is read correctly in every case: the name reaches the tracer as the intended characters, and only the stdout encoding differs.
Observed output
The 11.0.1 runs used the same binary, a fresh empty database on preprod, and the preprod config.yaml (UseTraceDispatcher: true) with only TraceOptionNodeName added.
TraceOptionNodeName |
Result |
stdout lines not valid UTF-8 |
talos-x |
runs normally |
0 |
talosü |
runs |
1 ("ApplicationName":"talos\x81") |
Günther |
runs |
1 ("ApplicationName":"G\x81nther") |
さん |
exits at startup |
0 (output stops mid-line) |
Günther + U+30FC + さん |
exits at startup |
1 ("ApplicationName":"G\x81nther, then output stops) |
stdout for talosü, start of line 3:
{"at":"2026-09-29T21:03:56.5008163Z","ns":"Reflection.TracerConfigInfo","data":{"conf":{"ApplicationName":"talos\x81","Forwarder":{"maxReconnectDelay":30,...
The bytes around the name are 74 61 6c 6f 73 81 22 2c.
For さん, stdout ends mid-line at {"at":"2026-09-29T21:31:37.4368255Z","ns":"Reflection.TracerConfigInfo","data":{"conf":{"ApplicationName":" and stderr contains:
cardano-node.exe: Uncaught exception ghc-internal:GHC.Internal.IO.Exception.SomeAsyncException:
ExceptionInLinkedThread (ThreadId 5) <stdout>: commitAndReleaseBuffer: invalid argument (cannot encode character '\12373')
While handling ExceptionInLinkedThread (ThreadId 5) <stdout>: commitAndReleaseBuffer: invalid argument (cannot encode character '\12373')
HasCallStack backtrace: throwIO, called at src/Cardano/Node/Handlers/TopLevel.hs:90:14 in cardano-node-11.0.1-9A2S7hSNaFUBV0TaMLmesA:Cardano.Node.Handlers.TopLevel
The combined name produces the same exception for '\12540' (U+30FC), after ü has already been written as 0x81.
Reproduced on 11.1.2 (the Windows binary distributed with Daedalus Mainnet 11.4.0, package id cardano-node-11.1.2-BZrVyWOIS7QHm71yCoNt2b), mainnet configuration, same method:
TraceOptionNodeName |
TRACE_DISPATCHER_LOGGING_HOSTNAME |
Result |
stdout lines not valid UTF-8 |
daedalus |
daedalus |
runs normally |
0 of 375 |
さん |
unset (host talos) |
exits at startup, cannot encode character '\12373' |
0 (output stops at "ApplicationName":") |
talos-x |
さん |
exits at startup, cannot encode character '\12373' |
0 (output stops at "host":" in the first JSON trace line) |
talos-x |
Günther |
runs |
374 of 376: every trace line carries "host":"G\x81nther" |
The 11.1.2 crash is rethrown from
src/Cardano/Node/Handlers/TopLevel.hs:161:18.
stderr, for an error whose message contains a path under a folder named
Güntherーさん (11.1.2, excerpt):
... CheckpointsReadFileError "C:\\Users\\...\\G\252nther\12540\12373\12435\\...\\checkpoints.json" C:\Users\...\G\x81nthercardano-node.exe: Uncaught exception ghc-internal:GHC.Internal.IO.Exception.IOException:
<stderr>: commitBuffer: invalid argument (cannot encode character '\12540')
Expected behavior
stdout, and in particular the machine-readable JSON trace lines, is UTF-8 on every platform regardless of the system code page, a character in a configured or derived name never terminates the node, and error messages on stderr are written in full.
Cause
Neither cardano-node nor trace-dispatcher sets an encoding on stdout, so the handle keeps GHC's default.
main goes straight to cryptoInit and runNode with no encoding setup: cardano-node/app/cardano-node.hs:27-37 at 11.1.3, identical at 11.1.2 and 11.0.1. The only hSetEncoding in the node's library code is for the trace documentation file, cardano-node/src/Cardano/Node/Tracing/Documentation.hs:911. The node's own test executables set hSetEncoding stdout utf8, for example cardano-node/test/cardano-node-test.hs:26.
- The stdout backend writes with
Data.Text.IO.putStrLn in a thread started with async and then linked: trace-dispatcher/src/Cardano/Logging/Tracer/Standard.hs:66-81 at trace-dispatcher-2.13.0 (lines 72 and 82 in 2.12.x, used by 11.0.1). An encoding exception in that thread therefore reaches the main thread as ExceptionInLinkedThread and is rethrown by the top-level handler (TopLevel.hs:161 at 11.1.3; line 90 at 11.0.1, as in the backtrace).
- In GHC 9.12.2 (the Windows compiler set by
windowsCompilerNixName = "ghc9122" in flake.nix:97 at 11.1.2 and 11.1.3, and at flake.nix:83 at 11.0.1), stdout is created with getLocaleEncoding (GHC/Internal/IO/Handle/FD.hs:73). On Windows the locale encoding is CodePage.localeEncoding (GHC/Internal/IO/Encoding.hs:208), which uses GetConsoleCP() when the process has a console and GetACP() otherwise, with ErrorOnCodingFailure (GHC/Internal/IO/Encoding/CodePage.hs:48-67). On the test host that is OEM code page 437 under a console (the node was started with a hidden console) or ANSI code page 1252 without one. Neither can encode さ.
- Two separate values carry the host name. The per-line
"host" field and the human-format prefix come from hostname in trace-dispatcher/src/Cardano/Logging/Formatter.hs:49-55, which is getHostName truncated at the first ., unless the TRACE_DISPATCHER_LOGGING_HOSTNAME environment variable is set (the same code is in trace-dispatcher 2.12.0, 2.12.1 and 2.13.0). TraceOptionNodeName only feeds ApplicationName, and when unset it defaults to getHostName plus the port in cardano-node/src/Cardano/Node/Startup.hs:263
(documented at configuration/cardano/mainnet-config.yaml:127-129).
11.1.3 was not run; its main has no encoding setup either.
Suggested fix
Set UTF-8 on the standard handles and the locale encoding at the top of main, before anything writes to stdout:
import qualified GHC.IO.Encoding as GHC
import System.IO (hSetEncoding, stderr, stdout, utf8)
main :: IO ()
main = do
GHC.setLocaleEncoding utf8
hSetEncoding stdout utf8
hSetEncoding stderr utf8
Crypto.cryptoInit
...
The explicit hSetEncoding calls make the result independent of whether stdout has already been evaluated when the locale encoding changes. Precedent: cardano-cli sets a UTF-8 locale encoding at startup since #4018 (
cardano-cli/app/cardano-cli.hs:46 at cardano-cli-11.2.3.1), after #3487 and #4244 reported the same commitAndReleaseBuffer error on Linux. cardano-wallet wraps main in withUtf8 from the with-utf8 package (lib/application/app/shelley/cardano-wallet.hs:199 at v2026-09-16).
Separately, an exception in the stdout writer thread terminates the whole node through link, so a logging failure stops block production and sync.
Workaround (not a fix)
Until stdout is UTF-8, an operator on an affected machine can keep non-ASCII text out of the trace output by setting both the TRACE_DISPATCHER_LOGGING_HOSTNAME environment variable and TraceOptionNodeName to ASCII values. This avoids the crash and the invalid bytes for these two fields only; any other non-ASCII string that reaches a trace line still hits the same encoding path. On Linux, running under a UTF-8 locale (for example LANG=C.UTF-8) avoids it.
System info (please complete the following information):
- OS Name: Windows (x86_64), English locale
- OS Version 25H2 26200.9457
- Code pages: ANSI 1252, OEM 437 (
[System.Text.Encoding]::Default.CodePage and
CultureInfo.CurrentCulture.TextInfo.OEMCodePage)
- Node versions tested: cardano-node 11.0.1 (Windows binary distributed with
Daedalus Pre-Prod 11.3.0, package id
cardano-node-11.0.1-9A2S7hSNaFUBV0TaMLmesA) and cardano-node 11.1.2 (Windows
binary distributed with Daedalus Mainnet 11.4.0, package id
cardano-node-11.1.2-BZrVyWOIS7QHm71yCoNt2b). The source analysis above is
against 11.1.2 and 11.1.3.
Screenshots and attachments
Raw stdout and stderr captures and the exact config.yaml for each run are available on request.
Linux
Tested on Linux with cardano-node 11.0.1 linux-x86_64 (git 97036a66, the static musl release binary), with the same configuration keys. The host name was also set to each test value with unshare -Ur --uts and sethostname.
| Locale |
talos-x |
Günther |
さん |
Günther + U+30FC + さん |
LANG=C.UTF-8 |
runs, valid UTF-8 |
runs, valid UTF-8 |
runs, valid UTF-8 |
runs, valid UTF-8 |
LC_ALL=C |
runs, valid UTF-8 |
exits 1 |
exits 1 |
exits 1 |
Under LC_ALL=C, any non-ASCII host name or node name stops the node at the first non-ASCII character it traces, with <stdout>: commitAndReleaseBuffer: invalid argument (cannot encode character '\252') ('\12373' for さん) and exit status 1. The human-format prefix on each line followed the host name set in the namespace, confirming that the host name reaches every trace line.
A Latin-1 locale could not be tested: the static musl binary ignores the locale and emits UTF-8.
Additional context
The node was launched by a PowerShell script through .NET System.Diagnostics.Process with UseShellExecute = false, CreateNoWindow = true and stdout and stderr redirected to pipes, then the pipes were copied byte for byte to files. The talos-x control and the Günther, さん and combined runs used the same non-ASCII install and database directories, and the talosü run used an ASCII directory, so the file paths are not a factor: the first stdout line, which prints the configuration with Haskell show, escapes those paths to ASCII.
Internal/External
External
Area
Other: tracing / stdout output on Windows.
Summary
On Windows, cardano-node writes its stdout trace output in the process's legacy code page instead of UTF-8. Two consequences follow from one cause:
TraceOptionNodeName: "talosü", theReflection.TracerConfigInfoline contains"ApplicationName":"talos\x81".0x81isüin OEM code page 437, the test host's OEM code page; UTF-8 would beC3 BCand CP1252, the host's ANSI code page, would beFC.<stdout>: commitAndReleaseBuffer: invalid argument (cannot encode character '\12373').The host name is the wider path: every trace line carries it, in the
"host"field of the JSON format and in the prefix of the human-readable format, and it comes fromgetHostNameindependently ofTraceOptionNodeName.TraceOptionNodeNameitself also defaults to the host name. On a machine whose computer name contains non-ASCII characters, every trace line is therefore affected under the stock configuration. Characters outside the code page (for example a Japanese, Chinese or Korean name on a machine whose code page is 437) stop the node at its first trace line; this was reproduced on 11.1.2 by setting the host name throughTRACE_DISPATCHER_LOGGING_HOSTNAME.The same applies to stderr: when an error message contains a path the code page cannot represent, such as one under a user profile whose name uses characters outside the code page, writing it fails, the encoding error replaces the original exception, and the message is cut off.
Steps to reproduce
config.yamland add one key:"TraceOptionNodeName": "talosü". Save the file as UTF-8.cardano-node.exe run --config config.yaml --topology topology.yaml --database-path db --socket-path \\.\pipe\node.socket --port 3001 > out.txt 2> err.txtout.txtas bytes. TheReflection.TracerConfigInfoline contains74 61 6c 6f 73 81 22(talos,0x81,"), which is not valid UTF-8."TraceOptionNodeName": "さん"(U+3055 U+3093). The node exits almost immediately anderr.txtcontains the exception quoted below."TraceOptionNodeName": "talos-x"runs normally and every stdout line is valid UTF-8.TraceOptionNodeNameand set the environment variableTRACE_DISPATCHER_LOGGING_HOSTNAME=Günther(orさん) before starting the node. This sets the samehostnamevalue that the node otherwise takes from the computer name.The configuration file is read correctly in every case: the name reaches the tracer as the intended characters, and only the stdout encoding differs.
Observed output
The 11.0.1 runs used the same binary, a fresh empty database on preprod, and the preprod
config.yaml(UseTraceDispatcher: true) with onlyTraceOptionNodeNameadded.TraceOptionNodeNametalos-xtalosü"ApplicationName":"talos\x81")Günther"ApplicationName":"G\x81nther")さんGünther+ U+30FC +さん"ApplicationName":"G\x81nther, then output stops)stdout for
talosü, start of line 3:The bytes around the name are
74 61 6c 6f 73 81 22 2c.For
さん, stdout ends mid-line at{"at":"2026-09-29T21:31:37.4368255Z","ns":"Reflection.TracerConfigInfo","data":{"conf":{"ApplicationName":"and stderr contains:The combined name produces the same exception for
'\12540'(U+30FC), afterühas already been written as0x81.Reproduced on 11.1.2 (the Windows binary distributed with Daedalus Mainnet 11.4.0, package id
cardano-node-11.1.2-BZrVyWOIS7QHm71yCoNt2b), mainnet configuration, same method:TraceOptionNodeNameTRACE_DISPATCHER_LOGGING_HOSTNAMEdaedalusdaedalusさんtalos)cannot encode character '\12373'"ApplicationName":")talos-xさんcannot encode character '\12373'"host":"in the first JSON trace line)talos-xGünther"host":"G\x81nther"The 11.1.2 crash is rethrown from
src/Cardano/Node/Handlers/TopLevel.hs:161:18.stderr, for an error whose message contains a path under a folder named
Güntherーさん(11.1.2, excerpt):Expected behavior
stdout, and in particular the machine-readable JSON trace lines, is UTF-8 on every platform regardless of the system code page, a character in a configured or derived name never terminates the node, and error messages on stderr are written in full.
Cause
Neither
cardano-nodenortrace-dispatchersets an encoding on stdout, so the handle keeps GHC's default.maingoes straight tocryptoInitandrunNodewith no encoding setup:cardano-node/app/cardano-node.hs:27-37at 11.1.3, identical at 11.1.2 and 11.0.1. The onlyhSetEncodingin the node's library code is for the trace documentation file,cardano-node/src/Cardano/Node/Tracing/Documentation.hs:911. The node's own test executables sethSetEncoding stdout utf8, for examplecardano-node/test/cardano-node-test.hs:26.Data.Text.IO.putStrLnin a thread started withasyncand thenlinked:trace-dispatcher/src/Cardano/Logging/Tracer/Standard.hs:66-81at trace-dispatcher-2.13.0 (lines 72 and 82 in 2.12.x, used by 11.0.1). An encoding exception in that thread therefore reaches the main thread asExceptionInLinkedThreadand is rethrown by the top-level handler (TopLevel.hs:161at 11.1.3; line 90 at 11.0.1, as in the backtrace).windowsCompilerNixName = "ghc9122"inflake.nix:97at 11.1.2 and 11.1.3, and atflake.nix:83at 11.0.1),stdoutis created withgetLocaleEncoding(GHC/Internal/IO/Handle/FD.hs:73). On Windows the locale encoding isCodePage.localeEncoding(GHC/Internal/IO/Encoding.hs:208), which usesGetConsoleCP()when the process has a console andGetACP()otherwise, withErrorOnCodingFailure(GHC/Internal/IO/Encoding/CodePage.hs:48-67). On the test host that is OEM code page 437 under a console (the node was started with a hidden console) or ANSI code page 1252 without one. Neither can encodeさ."host"field and the human-format prefix come fromhostnameintrace-dispatcher/src/Cardano/Logging/Formatter.hs:49-55, which isgetHostNametruncated at the first., unless theTRACE_DISPATCHER_LOGGING_HOSTNAMEenvironment variable is set (the same code is in trace-dispatcher 2.12.0, 2.12.1 and 2.13.0).TraceOptionNodeNameonly feedsApplicationName, and when unset it defaults togetHostNameplus the port incardano-node/src/Cardano/Node/Startup.hs:263(documented at
configuration/cardano/mainnet-config.yaml:127-129).11.1.3 was not run; its
mainhas no encoding setup either.Suggested fix
Set UTF-8 on the standard handles and the locale encoding at the top of
main, before anything writes to stdout:The explicit
hSetEncodingcalls make the result independent of whetherstdouthas already been evaluated when the locale encoding changes. Precedent:cardano-clisets a UTF-8 locale encoding at startup since #4018 (cardano-cli/app/cardano-cli.hs:46at cardano-cli-11.2.3.1), after #3487 and #4244 reported the samecommitAndReleaseBuffererror on Linux.cardano-walletwrapsmaininwithUtf8from thewith-utf8package (lib/application/app/shelley/cardano-wallet.hs:199at v2026-09-16).Separately, an exception in the stdout writer thread terminates the whole node through
link, so a logging failure stops block production and sync.Workaround (not a fix)
Until stdout is UTF-8, an operator on an affected machine can keep non-ASCII text out of the trace output by setting both the
TRACE_DISPATCHER_LOGGING_HOSTNAMEenvironment variable andTraceOptionNodeNameto ASCII values. This avoids the crash and the invalid bytes for these two fields only; any other non-ASCII string that reaches a trace line still hits the same encoding path. On Linux, running under a UTF-8 locale (for exampleLANG=C.UTF-8) avoids it.System info (please complete the following information):
[System.Text.Encoding]::Default.CodePageandCultureInfo.CurrentCulture.TextInfo.OEMCodePage)Daedalus Pre-Prod 11.3.0, package id
cardano-node-11.0.1-9A2S7hSNaFUBV0TaMLmesA) and cardano-node 11.1.2 (Windowsbinary distributed with Daedalus Mainnet 11.4.0, package id
cardano-node-11.1.2-BZrVyWOIS7QHm71yCoNt2b). The source analysis above isagainst 11.1.2 and 11.1.3.
Screenshots and attachments
Raw
stdoutandstderrcaptures and the exactconfig.yamlfor each run are available on request.Linux
Tested on Linux with cardano-node 11.0.1
linux-x86_64(git97036a66, the static musl release binary), with the same configuration keys. The host name was also set to each test value withunshare -Ur --utsandsethostname.talos-xGüntherさんGünther+ U+30FC +さんLANG=C.UTF-8LC_ALL=CUnder
LC_ALL=C, any non-ASCII host name or node name stops the node at the first non-ASCII character it traces, with<stdout>: commitAndReleaseBuffer: invalid argument (cannot encode character '\252')('\12373'forさん) and exit status 1. The human-format prefix on each line followed the host name set in the namespace, confirming that the host name reaches every trace line.A Latin-1 locale could not be tested: the static musl binary ignores the locale and emits UTF-8.
Additional context
The node was launched by a PowerShell script through .NET
System.Diagnostics.ProcesswithUseShellExecute = false,CreateNoWindow = trueand stdout and stderr redirected to pipes, then the pipes were copied byte for byte to files. Thetalos-xcontrol and theGünther,さんand combined runs used the same non-ASCII install and database directories, and thetalosürun used an ASCII directory, so the file paths are not a factor: the first stdout line, which prints the configuration with Haskellshow, escapes those paths to ASCII.