Aman-Mittal opened a new issue, #512:
URL: https://github.com/apache/fineract-backoffice-ui/issues/512
## What happens
`/loans/{loanId}/interest-pauses/edit/:variationId` takes its id straight
from the route:
```ts
//
src/app/features/loans/interest-pauses/interest-pause-form.component.ts:176
if (variationId) {
this.variationId = +variationId;
this.isEditMode.set(true);
this.loadPause();
}
```
The route has no constraint on the segment, so `edit/abc` gives `+'abc'` →
`NaN`. From there two guards disagree with `isEditMode`, because `NaN` is falsy:
```ts
private loadPause(): void {
if (!this.loanId || !this.variationId) return; // NaN → returns, form
stays empty
```
```ts
const save$ =
this.isEditMode() && this.variationId // NaN → falsy
? this.pauseService.putLoansLoanIdInterestPausesVariationId(...)
: this.pauseService.postLoansLoanIdInterestPauses(this.loanId, request);
// ← taken
```
So the header reads **Edit Interest Pause**, the pickers sit on today rather
than on the stored pause, and pressing Save creates a second pause instead of
correcting the first. Nothing on screen says so.
## Reproduced against a live platform
Loan 26 on the local stack: progressive, interest-recalculating, one pause
from 2026-08-17 to 2026-08-27.
Navigating to `/loans/26/interest-pauses/edit/abc`:

Picking 1–5 September and saving produced exactly one request, and it is a
create:
```
POST /fineract-provider/api/v1/loans/26/interest-pauses
{"startDate":"01 September 2026","endDate":"05 September
2026","dateFormat":"dd MMMM yyyy","locale":"en"}
```
No `PUT .../interest-pauses/{id}`, and no `GET` beforehand — `loadPause()`
had already returned. The list afterwards:

[Screen
recording](https://github.com/Aman-Mittal/fineract-backoffice-ui/raw/assets/issue-screenshots/interest-pause-edit-nan.webm).
## Why it matters
An interest pause changes what a borrower owes. A user who reaches this
screen from a stale link, a typo, or a bookmark that outlived a data reset gets
a screen that claims to be editing and silently grants a *second* relief period
on top of the first. The loan is then paused across two ranges the operator
never agreed to, and on a recalculating loan that is a real schedule change,
not a display artifact.
The same shape applies to `0` and to any id the segment cannot parse.
## Suggested fix
Reject an unusable id rather than falling through to create. Parse once, and
let the rest of the component depend on that one decision:
```ts
const parsed = Number(variationId);
if (!Number.isInteger(parsed) || parsed <= 0) {
// Not an id this screen can edit — send the user back to the list.
void this.router.navigate(['/loans', this.loanId, 'interest-pauses']);
return;
}
```
Whatever the handling, `isEditMode()` and the `save$` branch must not be
able to disagree — the bug is that they are derived from the same value by two
different truthiness rules. Deriving the mode from `variationId !== null` after
validation removes the possibility.
A route matcher constraining `:variationId` to digits would stop it earlier,
and is worth doing as well as, not instead of, the guard.
## Regression guard
A unit case asserting that a non-numeric route parameter does not call
`postLoansLoanIdInterestPauses`. The existing spec already stubs
`LoanInterestPauseService`, so this is one more case in the file, not new
scaffolding.
## Environment
`main` at `3c6d7479`. `apache/fineract:latest` via
`deploy/docker-compose-e2e.yml`, driven through the UI with no API seeding of
the request itself.
Found while reviewing #283 / PR #481 after it merged.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]