From 49a07ea76314405075fd492727101a7d57c6bab6 Mon Sep 17 00:00:00 2001 From: h1net Date: Sat, 14 Mar 2026 23:46:31 +0000 Subject: [PATCH 1/2] fix: handle missing exchange rates gracefully instead of crashing When exchange rate data is unavailable (e.g. on a fresh install before the data gathering job completes), toCurrencyAtDate() returned undefined. This propagated into new Big(undefined) in PortfolioCalculator and into number accumulations in PortfolioService, crashing the Overview, Portfolio and Holdings pages with "[big.js] Invalid number". Return 0 instead of undefined from toCurrencyAtDate() when no exchange rate can be found, consistent with the existing pattern in #6397. Add defensive ?? 0 guards at call sites in ActivitiesService and PortfolioService for additional safety. The error log is preserved so missing exchange rates are still flagged in the server logs without crashing the frontend. Fixes #6482 --- .../src/app/activities/activities.service.ts | 54 ++++++++++--------- .../src/app/portfolio/portfolio.service.ts | 8 +-- .../exchange-rate-data.service.ts | 2 +- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/apps/api/src/app/activities/activities.service.ts b/apps/api/src/app/activities/activities.service.ts index 89b9468f8..e686b456f 100644 --- a/apps/api/src/app/activities/activities.service.ts +++ b/apps/api/src/app/activities/activities.service.ts @@ -702,32 +702,34 @@ export class ActivitiesService { feeInBaseCurrency, unitPriceInAssetProfileCurrency, valueInBaseCurrency - ] = await Promise.all([ - this.exchangeRateDataService.toCurrencyAtDate( - order.fee, - order.currency ?? order.SymbolProfile.currency, - order.SymbolProfile.currency, - order.date - ), - this.exchangeRateDataService.toCurrencyAtDate( - order.fee, - order.currency ?? order.SymbolProfile.currency, - userCurrency, - order.date - ), - this.exchangeRateDataService.toCurrencyAtDate( - order.unitPrice, - order.currency ?? order.SymbolProfile.currency, - order.SymbolProfile.currency, - order.date - ), - this.exchangeRateDataService.toCurrencyAtDate( - value, - order.currency ?? order.SymbolProfile.currency, - userCurrency, - order.date - ) - ]); + ] = ( + await Promise.all([ + this.exchangeRateDataService.toCurrencyAtDate( + order.fee, + order.currency ?? order.SymbolProfile.currency, + order.SymbolProfile.currency, + order.date + ), + this.exchangeRateDataService.toCurrencyAtDate( + order.fee, + order.currency ?? order.SymbolProfile.currency, + userCurrency, + order.date + ), + this.exchangeRateDataService.toCurrencyAtDate( + order.unitPrice, + order.currency ?? order.SymbolProfile.currency, + order.SymbolProfile.currency, + order.date + ), + this.exchangeRateDataService.toCurrencyAtDate( + value, + order.currency ?? order.SymbolProfile.currency, + userCurrency, + order.date + ) + ]) + ).map((result) => result ?? 0); return { ...order, diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 5dab27939..4b88581ab 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -195,21 +195,21 @@ export class PortfolioService { switch (type) { case ActivityType.DIVIDEND: dividendInBaseCurrency += - await this.exchangeRateDataService.toCurrencyAtDate( + (await this.exchangeRateDataService.toCurrencyAtDate( new Big(quantity).mul(unitPrice).toNumber(), currency ?? SymbolProfile.currency, userCurrency, date - ); + )) ?? 0; break; case ActivityType.INTEREST: interestInBaseCurrency += - await this.exchangeRateDataService.toCurrencyAtDate( + (await this.exchangeRateDataService.toCurrencyAtDate( unitPrice, currency ?? SymbolProfile.currency, userCurrency, date - ); + )) ?? 0; break; } diff --git a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts index 024bdf4e1..8af434512 100644 --- a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts +++ b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts @@ -349,7 +349,7 @@ export class ExchangeRateDataService { 'ExchangeRateDataService' ); - return undefined; + return 0; } private async getExchangeRates({ From a6895d12b7ecb7a9016bc5a5b35a058a3fb450b0 Mon Sep 17 00:00:00 2001 From: h1net Date: Sat, 14 Mar 2026 23:47:16 +0000 Subject: [PATCH 2/2] docs: add changelog entry for exchange rate crash fix --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e2cdec28..22abf9ea4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Fixed a crash on the _Overview_, _Portfolio_ and _Holdings_ pages when exchange rate data is missing (e.g. before the data gathering job completes) - Fixed an issue with the detection of the thousand separator for the `de-CH` locale ## 2.249.0 - 2026-03-10