[BUG] - [BUG] - Windows: stdout uses the system code page, so JSON traces are not UTF-8 and unencodable characters crash the node
Los mantenedores suelen responder en 2 días
Ya se ha fusionado un pull request relacionado.
- #6731 de @mgmeier — fusionado
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 74/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- haskell
- Área
- observability
Línea de trabajo
Start with cardano-node/app/cardano-node.hs:27-37 and the standard-handle setup, then compare cardano-node/test/cardano-node-test.hs:26 and the trace-dispatcher stdout backend in Standard.hs. Reproduce on Windows with the listed non-ASCII node or host names, and verify stdout and stderr remain UTF-8 without startup or linked-thread encoding failures.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
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ü", 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. - 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.yamland 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.txtas bytes. TheReflection.TracerConfigInfoline contains74 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 anderr.txtcontains the exception quoted below. - Control:
"TraceOptionNodeName": "talos-x"runs normally and every stdout line is valid UTF-8. - Host name path: keep an ASCII
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 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.
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.- The stdout backend writes with
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). - In GHC 9.12.2 (the Windows compiler set by
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さ. - Two separate values carry the host name. The per-line
"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 atconfiguration/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.CodePageand
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.
- Lenguaje dominante
- Haskell
- Estrellas
- 3.2k
- Forks
- 763
- Merge medio
- 3 d 2 h
- PR fusionados (30 d)
- 22
Preparar el entorno
- Incluye un Dockerfile o un archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de IntersectMBO/cardano-node
-
Stale
Dificultad 1/5 1-3 horas Aptitud para principiantes 75/100
IntersectMBO/cardano-node#6597 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
IntersectMBO/cardano-node#6522 · 3 comentarios ·
Los mantenedores suelen responder en 2 días
-
Dificultad 4/5 3-5 días Aptitud para principiantes 45/100
IntersectMBO/cardano-node#6755 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
Dijkstra PV12 needs triage type: regression
Dificultad 5/5 Más de una semana Aptitud para principiantes 12/100
IntersectMBO/cardano-node#6748 ·
Los mantenedores suelen responder en 2 días
-
[cardano-testnet] Enhancements for status commandPosiblemente ocupada @palas la tomó hace 7 días. Abierto
IntersectMBO/cardano-node#6747 · 1 asignado ·
Los mantenedores suelen responder en 2 días
Todos los issues de IntersectMBO/cardano-node
Issues similares
-
no source repo for time-managerAbierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
yesodweb/wai#1163 · 1 reacción ·
Los mantenedores suelen responder en 1 día
-
Web.Scotty.Trans.Lazy.setHeader calls addHeader instead of setHeaderPosiblemente ocupada @tusharad la tomó hace 1 día. Abierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
scotty-web/scotty#436 ·
-
Broken links in the docsAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 70/100
input-output-hk/haskell.nix#2617 ·
-
easy first-contributor first-contributors good first issue haskell help wanted up-for-grabs
Dificultad 1/5 Menos de una hora Aptitud para principiantes 82/100
fork-commit-merge/fork-commit-merge#8455 ·
Los mantenedores suelen responder en 1 día
-
Add cabal-gild as fixerAbiertonew tool
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
dense-analysis/ale#5176 ·