[PR #5515] Fix: Crash when editing amount filter with locale-formatted numbers #13029

Closed
opened 2026-04-10 21:45:15 -05:00 by GiteaMirror · 0 comments
Owner

Original Pull Request: https://github.com/actualbudget/actual/pull/5515

State: closed
Merged: No


🐛 Fix: Crash when editing amount filter with locale-formatted numbers

This PR fixes a bug where editing an amount filter causes a crash when using number formats that rely on commas or other locale-specific separators, such as:

  • 1.000,33 (German-style)
  • 1’000.33 (Swiss-style)
  • 1 000,33 (French-style with space)

Bug Behavior

  • Users can create an amount filter like “is less than 1.000,33” — which works fine.
  • However, when they edit the filter (e.g., change “is less than” to “is greater than”), the app crashes with:
Error: safeNumber: number is not an integer: null
at safeNumber (util.ts:307:15)
at integerToCurrency (util.ts:319:20)
at FilterExpression.tsx:166:78

This is because the internal number parsing fails for some localized number strings, leading to null being passed into safeNumber().


🔍 Root Cause

The previous implementation didn't fully handle:

  • Grouping separators: ., ', space
  • Decimal separators: ,, .
  • Variants like 1 000,33, 1’000.33, etc.

These would parse incorrectly or return NaN, eventually leading to a crash when safeNumber(null) is called.


Solution

The fix includes:

1. Locale-Aware Parsing Layer

  • Introduced parseCurrencyString (strict + loose modes).
  • Used by currencyToAmount() and parseAmountFromEditorInput().

2. Editor Value Handling

  • In FilterExpression.tsx, changed how filter inputs are parsed and displayed:
    • Use formatAmountForEditor() to format numbers properly for input.
    • On save, parse user input back using parseAmountFromEditorInput() and pass it as an integer.

3. Safe Fallbacks

  • If parsing fails, null or 0 is returned (depending on usage), and crashes are avoided.

🧪 Tests

  • All existing tests pass except two:
expect(currencyToAmount('3.45060')).toBe(3.4506);
expect(currencyToAmount('3.456')).toBe(3.456);
  • These fail because the new parsing enforces a strict 2-decimal precision (which aligns with typical currency formatting).

  • Let me know if that precision should be relaxed or adjusted in a follow-up.


🛠 Modified Files

packages/loot-core/src/shared/util.ts
packages/desktop-client/src/components/filters/FilterExpression.tsx


🧩 Notes

  • This fix supports localized formats like:

    • 1.000,33
    • 1’000.33
    • 1 000,33
    • 1,000.33
  • Gracefully handles invalid input without crashing.

  • Handles both strict parsing (for controlled logic) and loose parsing (for flexible user input).

**Original Pull Request:** https://github.com/actualbudget/actual/pull/5515 **State:** closed **Merged:** No --- ## 🐛 Fix: Crash when editing amount filter with locale-formatted numbers This PR fixes a bug where editing an **amount filter** causes a crash when using number formats that rely on **commas or other locale-specific separators**, such as: - `1.000,33` (German-style) - `1’000.33` (Swiss-style) - `1 000,33` (French-style with space) --- ### ❗ Bug Behavior - Users can create an amount filter like “**is less than 1.000,33**” — which works fine. - However, when they **edit** the filter (e.g., change “is less than” to “is greater than”), the app crashes with: ``` Error: safeNumber: number is not an integer: null at safeNumber (util.ts:307:15) at integerToCurrency (util.ts:319:20) at FilterExpression.tsx:166:78 ``` This is because the internal number parsing fails for some localized number strings, leading to `null` being passed into `safeNumber()`. --- ### 🔍 Root Cause The previous implementation didn't fully handle: - **Grouping separators**: `.`, `'`, space - **Decimal separators**: `,`, `.` - Variants like `1 000,33`, `1’000.33`, etc. These would parse incorrectly or return `NaN`, eventually leading to a crash when `safeNumber(null)` is called. --- ### ✅ Solution The fix includes: #### 1. **Locale-Aware Parsing Layer** - Introduced `parseCurrencyString` (strict + loose modes). - Used by `currencyToAmount()` and `parseAmountFromEditorInput()`. #### 2. **Editor Value Handling** - In `FilterExpression.tsx`, changed how filter inputs are parsed and displayed: - Use `formatAmountForEditor()` to format numbers properly for input. - On save, parse user input back using `parseAmountFromEditorInput()` and pass it as an integer. #### 3. **Safe Fallbacks** - If parsing fails, `null` or `0` is returned (depending on usage), and crashes are avoided. --- ### 🧪 Tests - All **existing tests** pass **except two**: ```ts expect(currencyToAmount('3.45060')).toBe(3.4506); expect(currencyToAmount('3.456')).toBe(3.456); ``` - These fail because the new parsing enforces a strict 2-decimal precision (which aligns with typical currency formatting). - Let me know if that precision should be relaxed or adjusted in a follow-up. --- ### 🛠 Modified Files > packages/loot-core/src/shared/util.ts > packages/desktop-client/src/components/filters/FilterExpression.tsx --- ### 🧩 Notes - This fix supports localized formats like: - 1.000,33 - 1’000.33 - 1 000,33 - 1,000.33 - Gracefully handles invalid input without crashing. - Handles both strict parsing (for controlled logic) and loose parsing (for flexible user input).
GiteaMirror added the pull-request label 2026-04-10 21:45:15 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/actual#13029