Exception in _handleCardChanged#2265
Exception in _handleCardChanged#2265uristrimber wants to merge 5 commits intoflutter-stripe:mainfrom
Conversation
| try { | ||
| final map = Map<String, dynamic>.from(arguments); | ||
| final update = CardFieldInputDetails.fromJson( | ||
| Map<String, dynamic>.from(map['card']), |
There was a problem hiding this comment.
I see this nesting is still necesarry tested it with latest sdk on android
There was a problem hiding this comment.
the map doesn't have the 'card' value, it creates an exception and crashes.
There was a problem hiding this comment.
Does the UI works for you?.
We had to fork the package in PROD as it was throwing an eception
There was a problem hiding this comment.
I tested both android and ios and for the ui works. Can you give me some more details of the version of the package that you are using?
There was a problem hiding this comment.
Sorry I've been very busy, I'll send a demo ASAP.
There was a problem hiding this comment.
Perfect, I have an easy day so I can help you a little bit (with debbuging for ex.) if you need me.
There was a problem hiding this comment.
Want me do do the changes in the PR?
There was a problem hiding this comment.
@uristrimber when do you think you can make the changes. Would like to integrate it and take it along next version
There was a problem hiding this comment.
My AI code-checker wrote this, what do you think @remonh87?
consider applying the same fix to card_form_field.dart.
The nested is Map check handles both payload shapes safely:
Wrapped {card: {...}} → parses nested map.
Flat {...} (or missing card key / non-Map value) → falls back to the outer map, avoiding the Null is not a subtype of Map crash reported in this issue.
null is Map is false, so a missing card key gracefully hits the fallback.
One follow-up: packages/stripe/lib/src/widgets/card_form_field.dart (_handleCardChanged, lines ~505–527) still unconditionally does Map<String, dynamic>.from(map['card']) and would crash the same way if the platform ever emits a flat payload for the card form. Worth mirroring this defensive check there so the two widgets behave consistently.
Native layers send {card: {...}} for some card states and the flat
fields for others. Extract map['card'] when present and fall through
to the outer map otherwise so incomplete-card events stop crashing.
📝 WalkthroughWalkthroughThe card-change handler in the card field widget now conditionally checks the runtime type of the incoming Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/stripe/lib/src/widgets/card_field.dart (1)
544-547: Defensive unwrap handles both payload shapes.Native bridges on both iOS (
CardFieldView.swift/CardFormView.swift) and Android (CardChangeEvent.kt/CardFormCompleteEvent.kt) wrap the data under"card", so thenested is Mapbranch will be the normal path, while theelse mapbranch preserves compatibility with the flat payload that@uristrimberreported seeing in production. This lines up with the earlier suggestion to support both wrapped and flat shapes, and avoids the exception/crash described in#2265.One small note: once the dust settles, it would be worth confirming on a recent SDK whether the flat-payload case still actually occurs, and if not, logging (via
dev.log) when the fallback branch is taken so a future cleanup can remove it safely.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/stripe/lib/src/widgets/card_field.dart` around lines 544 - 547, Handle both wrapped ("card") and flat payload shapes when parsing card event data: read map['card'] into a local nested variable, set cardJson to Map<String, dynamic>.from(nested) if nested is Map else fallback to the original map, and pass cardJson into CardFieldInputDetails.fromJson to avoid crashes; keep the current defensive branch using the nested and cardJson variables and consider adding a dev.log when the fallback branch is taken for future cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/stripe/lib/src/widgets/card_field.dart`:
- Around line 544-547: Handle both wrapped ("card") and flat payload shapes when
parsing card event data: read map['card'] into a local nested variable, set
cardJson to Map<String, dynamic>.from(nested) if nested is Map else fallback to
the original map, and pass cardJson into CardFieldInputDetails.fromJson to avoid
crashes; keep the current defensive branch using the nested and cardJson
variables and consider adding a dev.log when the fallback branch is taken for
future cleanup.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4270cdd0-39a1-4788-ba4b-9a77dc7d746d
📒 Files selected for processing (1)
packages/stripe/lib/src/widgets/card_field.dart
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/stripe/lib/src/widgets/card_field.dart (1)
556-559: Conditional fallback looks correct; consider applying the same fix tocard_form_field.dart.The
nested is Mapcheck handles both payload shapes safely:
- Wrapped
{card: {...}}→ parses nested map.- Flat
{...}(or missingcardkey / non-Map value) → falls back to the outer map, avoiding theNull is not a subtype of Mapcrash reported in this issue.null is Mapisfalse, so a missingcardkey gracefully hits the fallback.One follow-up:
packages/stripe/lib/src/widgets/card_form_field.dart(_handleCardChanged, lines ~505–527) still unconditionally doesMap<String, dynamic>.from(map['card'])and would crash the same way if the platform ever emits a flat payload for the card form. Worth mirroring this defensive check there so the two widgets behave consistently.♻️ Optional: mirror the same pattern in
card_form_field.dart- } else { - final details = CardFieldInputDetails.fromJson( - Map<String, dynamic>.from(map['card']), - ); - controller._updateDetails(details); - widget.onCardChanged?.call(details); - } + } else { + final nested = map['card']; + final cardJson = + nested is Map ? Map<String, dynamic>.from(nested) : map; + final details = CardFieldInputDetails.fromJson(cardJson); + controller._updateDetails(details); + widget.onCardChanged?.call(details); + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/stripe/lib/src/widgets/card_field.dart` around lines 556 - 559, In _handleCardChanged in card_form_field.dart the code currently does an unconditional Map<String, dynamic>.from(map['card']) which can throw if map['card'] is null or not a Map; change it to mirror card_field.dart by first reading final nested = map['card']; then set final cardJson = nested is Map ? Map<String, dynamic>.from(nested) : map; and pass cardJson into CardFormFieldInputDetails.fromJson (or the existing parser used in _handleCardChanged) so the handler safely supports both wrapped {card: {...}} and flat payloads without crashing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/stripe/lib/src/widgets/card_field.dart`:
- Around line 556-559: In _handleCardChanged in card_form_field.dart the code
currently does an unconditional Map<String, dynamic>.from(map['card']) which can
throw if map['card'] is null or not a Map; change it to mirror card_field.dart
by first reading final nested = map['card']; then set final cardJson = nested is
Map ? Map<String, dynamic>.from(nested) : map; and pass cardJson into
CardFormFieldInputDetails.fromJson (or the existing parser used in
_handleCardChanged) so the handler safely supports both wrapped {card: {...}}
and flat payloads without crashing.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 936376d2-1882-4929-aab9-3ff6723cade1
📒 Files selected for processing (1)
packages/stripe/lib/src/widgets/card_field.dart
Fix: Revert card parsing logic in _handleCardChanged
This PR reverts the changes made to the input parsing logic in card_field.dart. The arguments map does not contain a nested 'card' key inside it.
Instead of incorrectly attempting to extract map['card'], this change reverts to passing the entire map directly to CardFieldInputDetails.fromJson.
Summary by CodeRabbit