fix(e2b): improve envd process client error handling and parsing#2196
fix(e2b): improve envd process client error handling and parsing#2196chcodex wants to merge 2 commits into
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
|
Suggest supplementary test |
AgentScopeJavaBot
left a comment
There was a problem hiding this comment.
🤖 AI Review
This PR improves the Connect protocol frame parsing in E2bEnvdProcessClient by properly handling end-stream frames (flag 0x02), compressed frames (flag 0x01), and unknown flags — replacing the previous naive flags != 0x00 check. It also adds SLF4J debug logging for better diagnosability and a clean parseEndStreamResponse() / EndStreamMessage record for end-stream error parsing. The changes are well-scoped and align with the Connect protocol specification. A few minor robustness gaps were identified around defensive null handling and a silently-swallowed exception that should be addressed for consistency with the new logging additions.
(inline comments could not be attached — line numbers fell outside PR hunks. See archived report.)
AgentScopeJavaBot
left a comment
There was a problem hiding this comment.
🤖 AI Review
This PR improves the Connect protocol frame parsing in E2bEnvdProcessClient by properly handling end-stream frames (flag 0x02), compressed frames (flag 0x01), and unknown flags — replacing the previous naive flags != 0x00 check. It also adds SLF4J debug logging for better diagnosability and a clean parseEndStreamResponse() / EndStreamMessage record for end-stream error parsing. The changes are well-scoped and align with the Connect protocol specification. A few minor robustness gaps were identified around defensive null handling and a silently-swallowed exception that should be addressed for consistency with the new logging additions.
(inline comments could not be attached — line numbers fell outside PR hunks. See archived report.)
- Parse EndStreamResponse (flags & 0x02) per Connect protocol spec - Use getField() instead of hasField() for proto3 scalar exit_code - Proto3 omits default values (0) from wire; getField() returns default - Extract EndEvent.error to stderr (signal-killed processes) - Fix JSON codec: always set end event when end node exists - Parsed error field from JSON (proto3_optional) - Reject compressed frames (flags & 0x01) with explicit error - Skip reserved flag bits (flags & 0xFC) - Add debug logging for frame processing diagnostics - Add 7 unit tests covering exit_code=0, EndStreamResponse, error field - Add integration test: signal-killed process via runShell + threads - Add evidence comments referencing Connect spec, Python SDK, Go handler
Summary
Fix E2B envd
process.Process/Startserver-streaming response parsing to correctly handle the Connect protocol Enveloped-Message frame format and proto3 scalar field semantics.Root Cause
sint32 exit_code = 1is a regular proto3 scalar field (not proto3_optional, not oneof). When exit code is 0, the field is omitted from both protobuf binary wire format and JSON output (proto3 default-value omission). The original code usedDynamicMessage.hasField()to check presence — returnsfalsefor default values — causing exit code 0 to be treated as "no exit code received", resulting inexitCode = -2147483648(Integer.MIN_VALUE).Changes
EndStreamMessage, throw on error, break cleanly on successIOExceptionhasField()+getField()withgetField()forexit_codeevent.event.end.exit_codeerrorfieldevent.event.end.errordirectly& 0x7FFFFFFFstrippedTests
Unit Tests (
E2bEnvdProcessClientTest) — 14 tests, 0 failuresExisting: codec selection, frame parsing, malformed base64, missing-end sentinel, single end frame.
New (7):
endStreamResponseWithErrorThrowsendStreamResponseWithoutErrorBreaksCleanly{}→ clean breakexitCodeZeroDefaultWhenOmittedend:{}(exitCode omitted) → exit=0 (proto3 default via getField)exitCodeNonZeroend:{exitCode:42}→ exit=42endEventErrorWrittenToStderrend:{error:"signal: 9"}→ stderr contains errorcompressedFrameThrowsIOExceptionreservedFlagsFrameIsSkippedIntegration Tests (
E2bEnvdProcessClientIntegrationTest) — 2 tests (require real sandbox +-DE2B_API_KEY)captureRawConnectFramessignalKillViaRunShellsleep 120viarunShell; Thread B kills viakillall; verifies EndEvent.error="signal: killed" captured to stderr throughdrainStartStreampipelineTest Plan