From 20edbe66a44589ccb9aed83800352f482cb0cba0 Mon Sep 17 00:00:00 2001 From: mefai-dev Date: Sun, 22 Mar 2026 19:22:00 +0000 Subject: [PATCH 1/3] fix(callbacks/v2): return nil on UnmarshalPacketData error in OnTimeoutPacket OnTimeoutPacket propagates UnmarshalPacketData errors, blocking the packet timeout lifecycle. This is inconsistent with OnSendPacket (line 124) and OnAcknowledgementPacket (line 254), both of which return nil on the same error, allowing the packet lifecycle to continue unblocked. The inconsistency is also visible in the comments: - OnSendPacket: "is not blocked if the packet does not opt-in to callbacks" (line 123) - OnAcknowledgementPacket: same comment (line 252) - OnTimeoutPacket: comment was missing (now added) The V1 callbacks middleware does not have this inconsistency because it uses a different pattern (GetSourceCallbackData combining unmarshal and callback data extraction). Impact: If a packet's payload cannot be unmarshalled by the callbacks middleware (e.g., codec version mismatch), the timeout transaction reverts entirely. The underlying app's OnTimeoutPacket has already executed the refund (line 317-320), but the revert rolls back all state changes. Since the packet has already timed out on the destination chain and cannot be received, the sender's funds become permanently locked with no recovery path. This aligns with the principle stated at line 359: "callback execution errors are not allowed to block the packet lifecycle." --- modules/apps/callbacks/v2/ibc_middleware.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/apps/callbacks/v2/ibc_middleware.go b/modules/apps/callbacks/v2/ibc_middleware.go index ebd64bb305c..6d02e1bdf26 100644 --- a/modules/apps/callbacks/v2/ibc_middleware.go +++ b/modules/apps/callbacks/v2/ibc_middleware.go @@ -320,15 +320,15 @@ func (im *IBCMiddleware) OnTimeoutPacket( } packetData, err := im.app.UnmarshalPacketData(payload) + // OnTimeoutPacket is not blocked if the packet does not opt-in to callbacks if err != nil { - return err + return nil } cbData, isCbPacket, err := types.GetCallbackData( packetData, payload.GetVersion(), payload.GetSourcePort(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas, types.SourceCallbackKey, ) - // OnTimeoutPacket is not blocked if the packet does not opt-in to callbacks if !isCbPacket { return nil } From 82fc4003a05c8a8f81ea154a5158f972c748e2ca Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 26 Mar 2026 18:07:52 +0300 Subject: [PATCH 2/3] docs: added deleted comment --- modules/apps/callbacks/v2/ibc_middleware.go | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/apps/callbacks/v2/ibc_middleware.go b/modules/apps/callbacks/v2/ibc_middleware.go index 6d02e1bdf26..41376705cc4 100644 --- a/modules/apps/callbacks/v2/ibc_middleware.go +++ b/modules/apps/callbacks/v2/ibc_middleware.go @@ -329,6 +329,7 @@ func (im *IBCMiddleware) OnTimeoutPacket( packetData, payload.GetVersion(), payload.GetSourcePort(), ctx.GasMeter().GasRemaining(), im.maxCallbackGas, types.SourceCallbackKey, ) + // OnTimeoutPacket is not blocked if the packet does not opt-in to callbacks if !isCbPacket { return nil } From 36cc64d3efe54f278f03a96df368a4a8610e4aa4 Mon Sep 17 00:00:00 2001 From: srdtrk Date: Thu, 26 Mar 2026 18:11:21 +0300 Subject: [PATCH 3/3] docs: added CHANGELOG entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c7419b4c70..deb62148ced 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes (apps/rate-limiting) [\#8767](https://github.com/cosmos/ibc-go/pull/8767) Fix string conflict in rate-limiting prefix iterator +(apps/callbacks) [\#8856](https://github.com/cosmos/ibc-go/pull/8856) OnTimeoutPacket blocked by UnmarshalPacketData error ### Testing API