Skip to content

fix(sdk-python,sdk-typescript): keep stream markers that end a log WebSocket message - #352

Open
TanishGudise wants to merge 1 commit into
daytona:mainfrom
TanishGudise:fix/log-demux-marker-boundary
Open

TanishGudise wants to merge 1 commit into
daytona:mainfrom
TanishGudise:fix/log-demux-marker-boundary

Conversation

@TanishGudise

@TanishGudise TanishGudise commented Oct 9, 2026 •

Copy link
Copy Markdown

Description

Streamed command and entrypoint logs could lose output, deliver stderr to the stdout callback, or leak raw \x01/\x02 marker bytes when a WebSocket message ended exactly on a complete 3-byte stream marker. This affected the demultiplexer shared by the sync and async Python SDKs (_std_demux_loop) and the TypeScript SDK's stdDemuxStream.

The demultiplexer holds back up to two trailing marker bytes in case a marker is split across messages, but it also searched for complete markers only in the bytes it had not held back, so a marker at the very end of a message was missed. With this change it searches the whole buffer for complete markers; the held-back length now only limits how much marker-free output is flushed. The Go and Java SDKs already behave this way. The fix is 2 lines in each SDK.

Tests (local only, nothing talks to the Daytona API):

  • sdk-python/tests/test_stream.py:
    • parametrized _std_demux_loop cases: single message; marker split 2+1 and 1+2; a message that is only a marker; a message ending with a stderr marker; a message ending with a stdout marker
    • AsyncProcess and sync Process get_session_command_logs_async against a local aiohttp WebSocket server that sends marker-aligned messages
  • sdk-typescript/src/__tests__/Stream.server.test.ts: the same cases through stdDemuxStream against a real local ws server, in the style of ConnectionRetry.server.test.ts

On main, 5 of the 8 new Python tests and 3 of the 6 new TypeScript tests fail; the split-marker and single-message controls pass. With this change, all of them pass.

Documentation

  • This change requires a documentation update
  • I have made corresponding changes to the documentation

No public API or docstring changes.

Related Issue(s)

Fixes #350

Screenshots

N/A

Notes

  • Checked locally:
    • yarn lint (lint:ts and lint:py: 0 errors) and the pre-commit lint-staged hooks
    • nx run sdk-typescript:test: 21 suites, 450 tests
    • the Python suite on 3.12: 716 passed
    • the new Python tests on 3.10 as well
  • I didn't run the Go, Java, Ruby or CLI test targets; this PR doesn't touch them.
  • test_event_subscription_manager.py::TestSyncEventSubscriptionManagerThreadUsage::test_many_subscriptions_share_one_expiry_thread fails intermittently on main too (a thread-count assertion; 2 of 8 local runs). It's unrelated to this change.
  • AI assistance: I developed this with help from Claude (Anthropic's AI assistant), which helped me find the bug, write the fix and tests, and draft this description. I reviewed the changes and test results before opening the PR.

🤖 Generated with Claude Code


Summary by cubic

Fixes the log demultiplexer in the Python and TypeScript SDKs so streamed command and entrypoint logs no longer lose output, misroute stderr, or leak raw marker bytes when a WebSocket message ends exactly on a complete stream marker. The demultiplexer held back up to two trailing marker bytes to handle markers split across messages, but only searched for complete markers in the bytes it did not hold back, so a marker at the very end of a message was missed. Now it searches the whole buffer for complete markers; the held-back length only bounds how much marker-free output is flushed, matching the Go and Java SDKs. Added regression tests for the sync and async Python SDKs and the TypeScript SDK against a real WebSocket server. Fixes #350.

Written for commit 36552b2. Summary will update on new commits.

View guided diff

…bSocket message

The stdout/stderr log demultiplexer holds back up to two trailing 0x01/0x02
bytes in case a marker is split across messages, but it also only searched
for complete markers inside the bytes it did not hold back. When a message
ended exactly on a complete marker, the marker was missed: its first byte was
emitted as payload, the other two were glued onto the next message, and the
stream type never switched. Callers saw raw marker bytes in their output,
stderr delivered to on_stdout, or output dropped entirely when no marker had
been recognized yet.

Search the whole buffer for complete markers; the held-back length now only
bounds how much marker-free payload may be flushed. This matches the Go and
Java SDKs. Covers the sync and async Python SDKs (shared _std_demux_loop) and
the TypeScript stdDemuxStream.

Fixes daytona#350

Signed-off-by: Tanish Gudise <174986239+TanishGudise@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vidoc-agent

vidoc-agent Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Vidoc security review

Tip

Good to merge — no security issues found. Reviewed 4 changed files.

💬 Have questions? Tag @vidoc in a comment and I'll answer.

@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA. ✅ Thank you!
Posted by the CLA Assistant Lite bot.

@TanishGudise

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Oct 9, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

View guided diff | Re-trigger cubic

This branch has not been deployed

No deployments
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.

sdk-python, sdk-typescript: streamed logs drop or misroute output when a WebSocket message ends on a stream marker

1 participant