Skip to content

Bug: EventBridgeV2Envelope raises UnicodeDecodeError for application/octet-stream payloads that are not UTF-8 JSON #8666

Open

Description

@alphasafal

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 UnicodeDecodeError instead of a ValidationError, so handlers that catch ValidationError miss 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 byte

Activity

  1. added
    bugSomething isn't working
    triagePending triage from maintainers
    on Oct 25, 2026
  2. leandrodamascena commented on Oct 25, 2026

    @leandrodamascena
    Contributor

    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, so bytes models get the payload and anything else raises ValidationError. 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.

  3. added
    parserParser (Pydantic) utility
    and removed
    triagePending triage from maintainers
    on Oct 25, 2026
  4. added this to the 3.38.0 milestone on Oct 25, 2026
  5. added a commit that references this issue on Oct 25, 2026
    c46af8c
  6. alphasafal commented on Oct 25, 2026

    @alphasafal
    Author

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingparserParser (Pydantic) utility

Type

No type

Projects

Relationships

None yet

Development

No branches or pull requests

Issue actions