format dispatch in read() has no fallback branch, so a value outside the union silently returns None (Python) rather than the file contents or an error.
Verified on staging with a real sandbox:
format='text' -> str: 'hello'
format='bytes' -> bytearray: bytearray(b'hello')
format='Text' -> NoneType: None # falls through every branch
format='txt' -> NoneType: None
The dispatch is if format == "text": ... elif format == "bytes": ... with no else, so control falls off the end of the function after the request has already succeeded. The caller gets None where content should be, with no exception and nothing to indicate the argument was wrong.
Affected (both Python mirrors, and the JS equivalents):
packages/python-sdk/e2b/sandbox_sync/filesystem/filesystem.py — read()
packages/python-sdk/e2b/sandbox_async/filesystem/filesystem.py — read()
packages/python-sdk/e2b/volume/volume_sync.py / volume_async.py — read()
packages/js-sdk/src/volume/index.ts — the fall-through is marked by a // format === 'blob' comment, so an unrecognized value silently returns a Blob rather than the requested shape
packages/js-sdk/src/sandbox/filesystem/index.ts — same shape
Literal / the TS union catch this for typed callers; it reaches anyone passing the value through from config, a CLI flag, or plain JS.
Suggested fix: an else: raise InvalidArgumentException(...) / throw new InvalidArgumentError(...) naming the valid formats, matching GitResetMode and GitConfigScope, which already validate their literal domains in both SDKs. Ideally before the request is issued rather than after, so a bad argument doesn't cost a round trip.
Related: the same class on onTimeout / onResume, where the value is coerced to a boolean before the request is built — being fixed in #1822. Those two are more severe (a mistyped on_timeout deletes the sandbox at timeout); this one is a wrong return value rather than data loss, which is why it's split out.
formatdispatch inread()has no fallback branch, so a value outside the union silently returnsNone(Python) rather than the file contents or an error.Verified on staging with a real sandbox:
The dispatch is
if format == "text": ... elif format == "bytes": ...with noelse, so control falls off the end of the function after the request has already succeeded. The caller getsNonewhere content should be, with no exception and nothing to indicate the argument was wrong.Affected (both Python mirrors, and the JS equivalents):
packages/python-sdk/e2b/sandbox_sync/filesystem/filesystem.py—read()packages/python-sdk/e2b/sandbox_async/filesystem/filesystem.py—read()packages/python-sdk/e2b/volume/volume_sync.py/volume_async.py—read()packages/js-sdk/src/volume/index.ts— the fall-through is marked by a// format === 'blob'comment, so an unrecognized value silently returns a Blob rather than the requested shapepackages/js-sdk/src/sandbox/filesystem/index.ts— same shapeLiteral/ the TS union catch this for typed callers; it reaches anyone passing the value through from config, a CLI flag, or plain JS.Suggested fix: an
else: raise InvalidArgumentException(...)/throw new InvalidArgumentError(...)naming the valid formats, matchingGitResetModeandGitConfigScope, which already validate their literal domains in both SDKs. Ideally before the request is issued rather than after, so a bad argument doesn't cost a round trip.Related: the same class on
onTimeout/onResume, where the value is coerced to a boolean before the request is built — being fixed in #1822. Those two are more severe (a mistypedon_timeoutdeletes the sandbox at timeout); this one is a wrong return value rather than data loss, which is why it's split out.