Problem
kalshi.fix.messages.decode_app_message(raw) returns None for two distinct cases:
- No registered model for the message type (admin / not-yet-implemented flow).
- A registered model whose payload failed schema validation (a malformed field).
Callers can't distinguish them. When the FIX flow is wired into a production consumer via FixSession(on_message=...), a genuine ExecutionReport that arrives with a single off-spec field (e.g. a DollarDecimal/FixedPointCount in an unexpected format) would be decoded to None and likely ignored — silently losing a fill. A logger.warning fires, but that only helps if logs are watched.
(Surfaced by the PR #431 automated review.)
Options
- A
FixDecodeError sentinel/exception — swallowed internally on the session dispatch path, surfaced to direct callers of decode_app_message.
- Return a
(FixMessage | None, Exception | None) tuple.
- An
on_decode_error hook on FixSession so consumers can route decode failures (dead-letter, halt, alert) without changing the FixMessage | None return type.
Option 3 fits the existing callback-based session ergonomics best and keeps the simple decode_app_message contract for casual callers.
Scope
Best landed with the typed inbound delivery / streaming ergonomics (the production-consumer wiring), not the message-layer PR #431. Part of #402; depends on #424.
Acceptance
A malformed inbound application message is observable by the consumer (not silently dropped), with a test that drives a malformed ExecutionReport through FixSession and asserts the error is surfaced via the chosen mechanism.
Problem
kalshi.fix.messages.decode_app_message(raw)returnsNonefor two distinct cases:Callers can't distinguish them. When the FIX flow is wired into a production consumer via
FixSession(on_message=...), a genuineExecutionReportthat arrives with a single off-spec field (e.g. aDollarDecimal/FixedPointCountin an unexpected format) would be decoded toNoneand likely ignored — silently losing a fill. Alogger.warningfires, but that only helps if logs are watched.(Surfaced by the PR #431 automated review.)
Options
FixDecodeErrorsentinel/exception — swallowed internally on the session dispatch path, surfaced to direct callers ofdecode_app_message.(FixMessage | None, Exception | None)tuple.on_decode_errorhook onFixSessionso consumers can route decode failures (dead-letter, halt, alert) without changing theFixMessage | Nonereturn type.Option 3 fits the existing callback-based session ergonomics best and keeps the simple
decode_app_messagecontract for casual callers.Scope
Best landed with the typed inbound delivery / streaming ergonomics (the production-consumer wiring), not the message-layer PR #431. Part of #402; depends on #424.
Acceptance
A malformed inbound application message is observable by the consumer (not silently dropped), with a test that drives a malformed
ExecutionReportthroughFixSessionand asserts the error is surfaced via the chosen mechanism.