Summary
On Windows with a non-UTF-8 locale, conductor run crashes with UnicodeEncodeError after the workflow has already completed successfully, while serializing its final JSON result to stdout. The workflow's real output is written correctly to disk, but:
- the JSON result on stdout is truncated mid-field, so it cannot be parsed by any caller;
- the process exits non-zero, so automation concludes the run failed;
- with
--web-bg, the dashboard shows "Connection lost — the Conductor process may have crashed", which reads as data loss.
The work is complete and safe on disk. Nothing in the UI or the exit status says so.
Environment
|
|
| Conductor |
v0.1.26 |
| Python |
3.10.11 |
| OS |
Windows 11, PowerShell 7 |
sys.stdout.encoding |
cp1252 (both redirected and at the console) |
PYTHONUTF8 / PYTHONIOENCODING |
unset (default) |
What I observed
A plan workflow ran ~55 minutes across 6 agent turns and finished. From the captured stderr, in this order:
✓ decision_summarizer (171.97s, claude-sonnet-4.6, 91851 in/59 out, $0.3046, → ['file_path'])
→ $end
⏱ Total workflow execution: 3317.76s
Workflow completed successfully
Token Usage Summary
Input: 1,050,049 tokens
...
Total: $6.1694
Event log written to: ...events.jsonl
+--------------------------- ❌ UnicodeEncodeError ---------------------------+
| 'charmap' codec can't encode character '\u2192' in position 190: |
| character maps to <undefined> |
+-----------------------------------------------------------------------------+
Workflow completed successfully is at stderr line 27412; UnicodeEncodeError at line 27432. The crash is strictly after successful completion.
The stdout JSON stops dead here:
{
"purpose": "...",
"plan_file": "...plan.md",
"decisions_file": "...decisions.md",
"technical_review_score": 92,
"readability_review_score": 93,
"technical_review_feedback": <-- ends mid-field, file ends here
ConvertFrom-Json rejects it. Both output documents (88 KB and 13 KB) were written to disk correctly.
Root cause
U+2192 (→) is not encodable in cp1252. Python 3.10 on Windows uses the locale encoding for sys.stdout unless PYTHONUTF8/PYTHONIOENCODING is set — and it does so whether or not stdout is redirected (verified below, this is not a redirection-only issue as I first assumed).
The failing write is the final result JSON, because it embeds agent-generated content — here technical_review_feedback, which contains →. Agent prose routinely contains → — ✅ ⚠️, so this is data-dependent: it fires whenever a reviewer/agent happens to use one, which makes it look intermittent.
Standalone reproduction (no workflow needed)
python -c "print('x'*185 + '\u2192')" > out.txt
# exit code: 1
# UnicodeEncodeError: 'charmap' codec can't encode character '\u2192'
# in position 185: character maps to <undefined>
# File "...\lib\encodings\cp1252.py", line 19, in encode
Identical codec, character, and error class as the conductor crash — only the offset differs, being a function of the string.
Encoding is cp1252 regardless of redirection
python -c "import sys; print(sys.stdout.encoding)" # cp1252
python -c "import sys; ..." > file.txt # cp1252
So --web-bg does not cause it — it makes it maximally alarming, because the dashboard interprets the dead process as a crashed run.
Impact
- Looks like total data loss. ~55 min and $6.17 of agent work appeared lost. It wasn't — but recovering it meant knowing to go read
%LOCALAPPDATA%\Temp\conductor\*.log and checking the output paths by hand.
- Breaks
--silent as a machine interface. Its contract is "JSON result only"; a truncated document is worse than none, because naive callers may parse a prefix.
- Non-zero exit on a successful run — CI and wrapper scripts will report failure.
- Silently intermittent. Depends on whether an agent emitted a non-cp1252 glyph, so it will not reproduce reliably for anyone triaging it.
Suggested fix
Force UTF-8 on conductor's own streams at entry, independent of locale:
# conductor/cli entrypoint, before any output
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
errors="replace" is worth having as a belt-and-braces measure: conductor should never die while reporting a result it already computed. Serializing the final result with ensure_ascii=True would also make the JSON path safe by construction.
Given that the same crash would kill a run mid-flight if the offending glyph appeared in progress output, the entrypoint fix looks preferable to patching individual call sites.
Related
Secondary observation (not diagnosed)
With conductor --silent run ... --web-bg, the dashboard URL never reached my console — I found Dashboard: http://127.0.0.1:52913 only inside the background process's redirected stderr log, and initially had to recover it by scanning listening TCP ports for the conductor PID. I have not verified whether this is --silent suppressing it or --web-bg emitting it only to the child's stream, so I am reporting the observation rather than asserting a cause. It matters because tooling built on this workflow is instructed to surface that URL to the user.
Summary
On Windows with a non-UTF-8 locale,
conductor runcrashes withUnicodeEncodeErrorafter the workflow has already completed successfully, while serializing its final JSON result to stdout. The workflow's real output is written correctly to disk, but:--web-bg, the dashboard shows "Connection lost — the Conductor process may have crashed", which reads as data loss.The work is complete and safe on disk. Nothing in the UI or the exit status says so.
Environment
sys.stdout.encodingcp1252(both redirected and at the console)PYTHONUTF8/PYTHONIOENCODINGWhat I observed
A
planworkflow ran ~55 minutes across 6 agent turns and finished. From the captured stderr, in this order:Workflow completed successfullyis at stderr line 27412;UnicodeEncodeErrorat line 27432. The crash is strictly after successful completion.The stdout JSON stops dead here:
{ "purpose": "...", "plan_file": "...plan.md", "decisions_file": "...decisions.md", "technical_review_score": 92, "readability_review_score": 93, "technical_review_feedback": <-- ends mid-field, file ends hereConvertFrom-Jsonrejects it. Both output documents (88 KB and 13 KB) were written to disk correctly.Root cause
U+2192 (→)is not encodable incp1252. Python 3.10 on Windows uses the locale encoding forsys.stdoutunlessPYTHONUTF8/PYTHONIOENCODINGis set — and it does so whether or not stdout is redirected (verified below, this is not a redirection-only issue as I first assumed).The failing write is the final result JSON, because it embeds agent-generated content — here
technical_review_feedback, which contains→. Agent prose routinely contains→ — ✅ ⚠️, so this is data-dependent: it fires whenever a reviewer/agent happens to use one, which makes it look intermittent.Standalone reproduction (no workflow needed)
Identical codec, character, and error class as the conductor crash — only the offset differs, being a function of the string.
Encoding is cp1252 regardless of redirection
So
--web-bgdoes not cause it — it makes it maximally alarming, because the dashboard interprets the dead process as a crashed run.Impact
%LOCALAPPDATA%\Temp\conductor\*.logand checking the output paths by hand.--silentas a machine interface. Its contract is "JSON result only"; a truncated document is worse than none, because naive callers may parse a prefix.Suggested fix
Force UTF-8 on conductor's own streams at entry, independent of locale:
errors="replace"is worth having as a belt-and-braces measure: conductor should never die while reporting a result it already computed. Serializing the final result withensure_ascii=Truewould also make the JSON path safe by construction.Given that the same crash would kill a run mid-flight if the offending glyph appeared in progress output, the entrypoint fix looks preferable to patching individual call sites.
Related
PYTHONIOENCODING=utf-8"fixes Python's own stdout", which suggests the stdout path was assumed handled; this shows it is not, in the default case where that variable is unset.--web-bgchild process dies when launched from a job-managed shell on Windows (missing CREATE_BREAKAWAY_FROM_JOB) #195 (--web-bgchild dies on Windows) — also--web-bg+ Windows, but that is process-lifetime (job objects); this is stream encoding. Distinct.Secondary observation (not diagnosed)
With
conductor --silent run ... --web-bg, the dashboard URL never reached my console — I foundDashboard: http://127.0.0.1:52913only inside the background process's redirected stderr log, and initially had to recover it by scanning listening TCP ports for the conductor PID. I have not verified whether this is--silentsuppressing it or--web-bgemitting it only to the child's stream, so I am reporting the observation rather than asserting a cause. It matters because tooling built on this workflow is instructed to surface that URL to the user.