fix: empty string in response and more logging
What changed, and why it matters
This commit fixes a minor app crash and adds better error logging. The app was failing when a backend response contained an empty VAT rate field, because the code expected a number and couldn't handle an empty string. The fix makes the VAT rate optional and safely parses it. The logging change helps developers see what went wrong during invoice loading.
No immediate security action required. Treat as a routine stability/robustness fix. Consider reviewing other JSON deserialization paths for similar non-null assumptions and adding regression tests for empty-string numeric fields.
Security signals we found
Input parsing made more defensive against unexpected API responses
Silent exception swallowing replaced with structured logging
Nullable type change suggests prior assumption of always-present numeric field was incorrect
Evidence from the diff
The patch addresses a deserialization robustness issue in the ShopInBit ticket model. _toInt(json['vat_rate']) is replaced with int.tryParse(json['vat_rate'].toString()), and the vatRate field is changed from non-nullable int to nullable int?. This prevents a TypeError or FormatException when vat_rate is an empty string or otherwise non-numeric. Additionally, the catch block in _loadResumableInvoice now logs the exception and stack trace instead of silently swallowing errors.
Changed components
lib/services/shopinbit/src/models/ticket.dartlib/pages/shopinbit/shopinbit_tickets_view.dartInspect captured patch +9 / −3
diff --git a/lib/pages/shopinbit/shopinbit_tickets_view.dart b/lib/pages/shopinbit/shopinbit_tickets_view.dart
index aaecb69..3f941d5 100644
--- a/lib/pages/shopinbit/shopinbit_tickets_view.dart
+++ b/lib/pages/shopinbit/shopinbit_tickets_view.dart
@@ -10,6 +10,7 @@ import "../../providers/global/shopin_bit_service_provider.dart";
import "../../services/shopinbit/src/models/car_research.dart";
import "../../themes/stack_colors.dart";
import "../../utilities/assets.dart";
+import "../../utilities/logger.dart";
import "../../utilities/text_styles.dart";
import "../../utilities/util.dart";
import "../../widgets/background.dart";
@@ -88,7 +89,12 @@ class _ShopInBitTicketsViewState extends ConsumerState<ShopInBitTicketsView> {
}
}
}
- } catch (_) {
+ } catch (e, s) {
+ Logging.instance.e(
+ "_loadResumableInvoice failed",
+ error: e,
+ stackTrace: s,
+ );
// Leave _resumableInvoice unchanged on failure.
return;
}
diff --git a/lib/services/shopinbit/src/models/ticket.dart b/lib/services/shopinbit/src/models/ticket.dart
index 52ee9fd..db055be 100644
--- a/lib/services/shopinbit/src/models/ticket.dart
+++ b/lib/services/shopinbit/src/models/ticket.dart
@@ -115,7 +115,7 @@ class TicketFull {
final String? netPurchasePrice;
final String? netShippingCosts;
final String deliveryCountry;
- final int vatRate;
+ final int? vatRate;
TicketFull({
required this.id,
@@ -143,7 +143,7 @@ class TicketFull {
deliveryCountry:
json['delivery_country'] as String? ??
(json['deliverycountry'] as String),
- vatRate: _toInt(json['vat_rate']),
+ vatRate: int.tryParse(json['vat_rate'].toString()),
);
}
Why this scored 20/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.