files.read / volume.read return None for an unrecognized format instead of raising
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: NoneThe 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 shapepackages/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.
Source: e2b-dev/E2B