Skip to content

The unity plugin scripts decode child output strictly behind TimeoutExpired/OSError guards #607

Description

@pbean

The shipped unity plugin scripts capture child output with text=True behind guards that name only TimeoutExpired/OSError — the same narrow-net defect #380 and #383 closed in orchestrator core, still open in plugin data.

The defect genus

subprocess.run(..., text=True) decodes with the locale codec at errors="strict". The fault that raises is UnicodeDecodeError — a UnicodeError, so a ValueError. It is neither an OSError nor a SubprocessError, so a guard naming only those does not catch it, and the decode happens after the child has exited, so a child that succeeded takes its exit code down with the raise.

That is the same shape as #383 (plugins/bus.py, probe.py) and the decode half of #380 (adapters/tmux_base.py). Those were fixed by adding errors="replace" — stop raising, rather than catch more.

Sites

Under src/bmad_loop/data/plugins/unity/:

  • unity_ready.py:113 (wait-for-ready) and unity_ready.py:129 (run-tool) — both guarded by except subprocess.TimeoutExpired only. Output is sliced ([-500:]) into hook advisory text.
  • unity_quiesce.py:111
  • unity_plugin.py:408
  • unity_setup.py:182, :324, and :402:402 (setup-mcp) has no try at all; it writes proc.stdout + proc.stderr straight to stderr.

The decoded bytes are output from the Unity CLI and the Editor bridge — an operator's own toolchain, not a path, so nothing constrains them to the run's encoding. A project path, asset name or C# diagnostic carrying a non-UTF-8 byte under a non-UTF-8 locale is enough.

Why it was not folded into the #380/#383 fix

These are shipped plugin data, not orchestrator core, and neither issue names them. Folding them in would have widened a bundled fix past the two issues it closes. Filed separately so the decision is recorded rather than implied.

Asked for

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Robustness, enhancement, tests, or docs worth schedulingarea:engineOrchestrator engine and run lifecyclebugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions