Skip to content

fix(price): tolerate unpriced /realunit/price payloads without crashing#701

Closed
TaprootFreak wants to merge 1 commit into
stagingfrom
fix/price-null-handling
Closed

fix(price): tolerate unpriced /realunit/price payloads without crashing#701
TaprootFreak wants to merge 1 commit into
stagingfrom
fix/price-null-handling

Conversation

@TaprootFreak
Copy link
Copy Markdown
Contributor

Problem

The live /v1/realunit/price endpoint returns only {"timestamp": ...} (no chf/eur) while no price is published for the day, and the newest /v1/realunit/price/history entry carries the same unpriced shape. DFXPriceService multiplied the missing fields (null * 100), throwing an unhandled NoSuchMethodError from DashboardBloc._onRefreshPriceEvent / _onRefreshPriceChartEvent on every dashboard price refresh — reproducible against DEV and PRD today. The price renders as CHF --.-- only because the bloc zone swallows the exception.

Unhandled Exception: NoSuchMethodError: The method '*' was called on null.
#1  DFXPriceService.getPriceOfAsset (dfx_price_service.dart:66)
#2  DashboardBloc._onRefreshPriceEvent (dashboard_bloc.dart:46)

Root fix

  • New RealUnitPriceDto (nullable chf/eur/timestamp): the wire shape is parsed in one typed, null-safe place — removes the inline JSON parsing from the service (CONTRIBUTING DTO rule).
  • getPriceOfAsset: requested currency absent → BigInt.zero; the dashboard already renders the zero sentinel as --.-- (dashboard_price_widget.dart:82, DashboardState initial value).
  • getPriceChart: skips entries that are unpriced or have no parseable timestamp; PriceChartCubit already handles partial/empty lists.
  • getChfToEurRate: null-safe via the existing chf > 0 guard (→ 0.0).

Behavior for fully-priced payloads is bit-identical (same value * 100 double arithmetic); non-200 still throws.

Tests

  • Service: unpriced spot payload (CHF + EUR), skipped unpriced history entries, missing/unparseable timestamps, unpriced getChfToEurRate.
  • New RealUnitPriceDto spec: full parse, int coercion, timestamp-only payload, absent/non-string/unparseable timestamp.
  • Golden: dashboard_price_no_chart locks the "price present, history unpriced → chart empty" dashboard rendering (deterministic: empty chart takes the zero-window path before DateTime.now()).
  • flutter analyze clean · full suite 2316 passed · golden suite 103 passed · scoped coverage stays 100% (floor met).

Notes

  • Found during a full local staging test run on M5 (unit+widget+golden suites, Android emulator smoke vs DEV API).
  • API-side follow-up worth considering in DFXswiss/api: omit unpriced entries from /v1/realunit/price/history or document the unpriced shape in Swagger.

The live /v1/realunit/price endpoint returns only {"timestamp": ...}
while no price is published for the day, and the newest
/v1/realunit/price/history entry carries the same unpriced shape. The
inline parsing in DFXPriceService multiplied these missing fields
(null * 100), throwing an unhandled NoSuchMethodError from
DashboardBloc on every dashboard price refresh (reproducible on DEV
and PRD).

Root fix:
- Add RealUnitPriceDto with nullable chf/eur/timestamp so the wire
  shape is parsed in one typed, null-safe place (no more inline JSON
  parsing in the service).
- getPriceOfAsset returns BigInt.zero when the requested currency is
  absent; the dashboard already renders the zero sentinel as "--.--".
- getPriceChart skips entries that are unpriced or carry no parseable
  timestamp instead of crashing; partial/empty lists are already
  handled by PriceChartCubit.
- getChfToEurRate falls back to 0.0 via the existing chf > 0 guard.

Tests pin every new branch (unpriced spot payload per currency,
skipped history entries, missing/invalid timestamps, DTO parsing);
scoped coverage stays at 100%. A new dashboard golden
(dashboard_price_no_chart) locks the "price present, history
unpriced" rendering.
@TaprootFreak
Copy link
Copy Markdown
Contributor Author

BUG#1 already fixed in staging by #695/#694; branch built on stale staging, redundant

@TaprootFreak TaprootFreak deleted the fix/price-null-handling branch June 5, 2026 21:01
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