Skip to content

feat: shim the consumer-side tombstone fix too, until faststream releases it - #20

Merged
aradng merged 1 commit into
mainfrom
fix/revert-git-dep-restore-shim
Jul 13, 2026
Merged

feat: shim the consumer-side tombstone fix too, until faststream releases it#20
aradng merged 1 commit into
mainfrom
fix/revert-git-dep-restore-shim

Conversation

@aradng

@aradng aradng commented Jul 13, 2026

Copy link
Copy Markdown
Owner

#19 merged into fix/revert-git-dep-restore-shim (its stacked base) instead of main by mistake - that branch was never subsequently merged into main, so the consumer-side shim never actually landed or published. This is the same content, now targeting main directly.

ag2ai/faststream#2933 (Optional[Model] = None should resolve correctly for a real tombstone instead of crash-looping on required fields) is open upstream, unmerged, no PyPI release either way. The producer side already gets this treatment via _patch_real_tombstones (0.4.48/0.4.50) - this does the same for the consumer side, so both halves actually work today instead of only the producer.

Three patches, each guarded for idempotency:

  • AsyncConfluentParser.parse_message: tags the body with a dedicated TOMBSTONE sentinel (not a byte pattern like b"null"/b"" - can't collide with real message content) when the raw value is a genuine null.
  • AsyncConfluentParser.decode_message: maps TOMBSTONE to None.
  • faststream._internal.fastapi.route.build_faststream_to_fastapi_parser: a full replacement, since it's a per-subscriber closure factory rather than a patchable class method. Passes a real None through instead of wrapping it as {param_name: None} - that wrapping is exactly what defeats FastAPI's own no-body shortcut and forces field-level validation on every tombstone instead.

Bumps to 0.4.51.

Test plan

  • New test in tests/kafka/test_tombstone.py: Optional[Model] = None resolves to None for a real tombstone against a real broker, valid payloads still parse correctly.
  • Confirmed the test fails without the shim, passes with it.
  • Full tests/kafka/ suite passes (19/19).
  • ruff + mypy clean.

…ases it (#19)

ag2ai/faststream#2933 (Optional[Model] = None resolving correctly for a
real tombstone instead of crash-looping on required fields) is open,
unmerged, no PyPI release. Producer-side already gets the equivalent
treatment via _patch_real_tombstones - do the same here so both halves
work today, not just once faststream ships something.

Three patches, each guarded for idempotency:
- AsyncConfluentParser.parse_message: tags the body with a dedicated
  TOMBSTONE sentinel (not a byte pattern - can't collide with real
  content) when the raw value is a genuine null.
- AsyncConfluentParser.decode_message: maps TOMBSTONE to None.
- faststream._internal.fastapi.route.build_faststream_to_fastapi_parser:
  a full replacement (it's a per-subscriber closure factory, not a
  patchable class method) that passes a real None through instead of
  wrapping it as {param_name: None} - that wrapping is what defeats
  FastAPI's own no-body shortcut and forces field-level validation on
  every tombstone.

Bumps to 0.4.51.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
@aradng
aradng force-pushed the fix/revert-git-dep-restore-shim branch from bdafb36 to 5555db7 Compare July 13, 2026 19:40
@aradng
aradng merged commit b0ff169 into main Jul 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant