Repository navigation
Bug: EventBridgeV2Envelope raises UnicodeDecodeError for application/octet-stream payloads that are not UTF-8 JSON #8666
Description
Expected Behaviour
The Parser envelope handles an application/octet-stream record the same way the EventBridgeV2Event data class does: the payload is available as bytes, so a bytes model gets the raw payload, and a model the payload doesn't match raises a ValidationError.
Current Behaviour
EventBridgeV2Envelope.parse (added in #8658) always runs payload.decode() on octet-stream bytes and passes the resulting str to _parse, which treats every str as JSON. Only octet-stream payloads that happen to be UTF-8 JSON work, which is the case test_envelope_parses_octet_stream_json_bytes covers.
- Binary payloads (images, gzip, protobuf) raise a raw
UnicodeDecodeErrorinstead of aValidationError, so handlers that catchValidationErrormiss it. - Plain-text payloads fail validation even with
model=bytes.
The data class returns the bytes for all of these, so the two APIs disagree on the same event.
Code snippet
import base64
from pydantic import BaseModel
from aws_lambda_powertools.utilities.data_classes import EventBridgeV2Event
from aws_lambda_powertools.utilities.parser import envelopes, parse
class Order(BaseModel):
order_id: str
def octet_stream_event(payload: bytes) -> dict:
return {
"Data": base64.b64encode(payload).decode(),
"Metadata": {},
"SystemMetadata": {"ContentType": "application/octet-stream", "aws:DeliveryType": "LIVE"},
}
for payload, model in ((b"\xff\xd8\xff\xe0JFIF", bytes), (b"hello world", bytes), (b"\xff\xd8\xff\xe0JFIF", Order)):
event = octet_stream_event(payload)
print(f"payload={payload!r} model={model.__name__}")
print(" data class:", next(iter(EventBridgeV2Event(event).records)).data)
try:
print(" parser :", parse(event=event, model=model, envelope=envelopes.EventBridgeV2Envelope))
except Exception as exc:
print(f" parser : {type(exc).__module__}.{type(exc).__name__}: {str(exc).splitlines()[0]}")Possible Solution
For octet-stream bytes, try json.loads(payload) and fall back to passing the raw bytes to the model when it isn't JSON (json.loads raises ValueError for both invalid UTF-8 and invalid JSON). The JSON case keeps working as today, a bytes model gets the raw payload, and other models raise ValidationError. I have this ready with tests (all parser and data class tests pass) and am happy to open the PR.
Steps to Reproduce
Run the snippet above.
Powertools for AWS Lambda (Python) version
latest (develop @ 5785377)
AWS Lambda function runtime
3.13
Packaging format used
PyPi
Debugging logs
Output of the snippet on develop:
payload=b'\xff\xd8\xff\xe0JFIF' model=bytes
data class: b'\xff\xd8\xff\xe0JFIF'
parser : builtins.UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
payload=b'hello world' model=bytes
data class: b'hello world'
parser : pydantic_core._pydantic_core.ValidationError: 1 validation error for bytes
payload=b'\xff\xd8\xff\xe0JFIF' model=Order
data class: b'\xff\xd8\xff\xe0JFIF'
parser : builtins.UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byteMetadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTriage
Activity
leandrodamascena commentedon Oct 25, 2026
Thanks @alphasafal, confirmed, and this one is on me: the
decode()went in with the last push on #8658 and I only tested JSON bytes. Your approach is right, try JSON first and hand the raw bytes to the model otherwise, sobytesmodels get the payload and anything else raisesValidationError. It's yours. This has to land before 3.38.0 ships, so if you can open the PR in the next couple of days, great, otherwise I'll push the fix myself and credit you.fix(parser): pass non-JSON octet-stream payloads to the model in Even…
alphasafal commentedon Oct 25, 2026
Thanks @leandrodamascena! PR is up: #8669. Try JSON first, fall back to the raw bytes, with tests for the binary, plain-text and object-model cases.