Skip to content

Avoid a Buildbot bug that can hang CTest steps forever - #371

Merged
alexreinking merged 1 commit into
masterfrom
areinking/ctest-avoid-unicodedecode-hang
Sep 3, 2026
Merged

Avoid a Buildbot bug that can hang CTest steps forever#371
alexreinking merged 1 commit into
masterfrom
areinking/ctest-avoid-unicodedecode-hang

Conversation

@alexreinking

Copy link
Copy Markdown
Member

Summary

  • We've had buildbot workers get stuck for days, occupying a build slot and holding performance_lock forever on that worker, starving any sibling step needing exclusive access (e.g. performance tests). This happened even when the superseding-commit cancellation service tried to cancel the offending build -- there was nothing left to cancel, because the step wasn't running a command or waiting on a lock; it was permanently parked inside a hung file transfer.
  • Root cause (confirmed against production master logs and DB, byte-for-byte): CTest.run() fetches the CTest XML results file from the worker via getFileContentFromWorker(), which uses buildbot's StringFileWriter. That class decodes each 32KB transfer chunk as UTF-8 independently (buildbot/process/remotetransfer.py), so a multi-byte character split across a chunk boundary raises UnicodeDecodeError inside a Twisted PB remote-message handler -- not through buildbot's normal command-failure path -- so the step is never notified and hangs forever.
  • This is a long-standing, still-open upstream bug: buildbot/buildbot#3982 (filed 2018). A 2019 fix attempt, buildbot/buildbot#4621, stalled in review and was closed by stale-bot without landing. It's still present in the pinned buildbot~=4.0 (currently resolving to 4.3.0), so there's no version bump that avoids it.
  • Fix: since Xml.fromstring() accepts bytes directly, we don't need decoded text at all here. Added a small _BytesFileWriter (a FileWriterImpl that keeps raw bytes) and a local getFileBytesFromWorker() in custom_steps.py, sidestepping the bug entirely instead of working around its symptoms.

Test plan

  • Reproduced the exact production failure (UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe2 in position 32767: unexpected end of data) standalone by feeding a chunk-boundary-split multi-byte character through buildbot's real StringFileWriter, and confirmed the new _BytesFileWriter parses the same input cleanly via Xml.fromstring.
  • uv run ruff check / ruff format --check on master/custom_steps.py
  • uv run ty check master/custom_steps.py
  • buildbot checkconfig .
  • After merge/deploy, watch for any CTest step that previously would have hung to complete normally instead

🤖 Generated with Claude Code

CTest.run() fetches the ctest XML results file from the worker via
getFileContentFromWorker(), which uses buildbot's StringFileWriter. That
class decodes each 32KB transfer chunk as UTF-8 independently
(buildbot/process/remotetransfer.py), so a multi-byte character split
across a chunk boundary raises UnicodeDecodeError inside a PB
remote-message handler rather than through buildbot's normal
command-failure path. The step is never notified, so it hangs forever,
still holding its counting-mode claim on performance_lock -- which then
starves any sibling step on the same worker that needs exclusive access
to that lock (e.g. the performance test steps), for however long it takes
someone to notice and restart the master.

This is a long-standing, still-open upstream bug (buildbot/buildbot#3982);
a 2019 fix attempt (buildbot/buildbot#4621) stalled in review and was
closed by stale-bot without landing, and it's still present in the pinned
4.3.0 release, so there's no version bump that avoids it.

Since Xml.fromstring() accepts bytes directly, we don't need decoded text
here at all: read the file as raw bytes via a small custom FileWriterImpl
instead of buildbot's decoding one, sidestepping the bug rather than
working around its symptoms.

Confirmed against a byte-for-byte reproduction of the production failure
(same "position 32767: unexpected end of data" error) that the old writer
raises and the new one doesn't.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@alexreinking
alexreinking merged commit d17cbc5 into master Sep 3, 2026
9 checks passed
@alexreinking
alexreinking deleted the areinking/ctest-avoid-unicodedecode-hang branch September 3, 2026 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant