Skip to content

(WEB-370): Handle Fineract 500 errors gracefully for provisioning entries#3284

Open
YousufFFFF wants to merge 1 commit intoopenMF:devfrom
YousufFFFF:fix-provisioning-entry-error-handling
Open

(WEB-370): Handle Fineract 500 errors gracefully for provisioning entries#3284
YousufFFFF wants to merge 1 commit intoopenMF:devfrom
YousufFFFF:fix-provisioning-entry-error-handling

Conversation

@YousufFFFF
Copy link
Member

@YousufFFFF YousufFFFF commented Mar 3, 2026

Description:

The Create Provisioning Entry flow was displaying a false "Internal Server Error"
toast even when the entry was created successfully. This is caused by a known
Apache Fineract backend bug where provisioning entry endpoints return HTTP 500
despite completing the operation successfully.

Changes made:

  • Added an error handler in create-provisioning-entry.component.ts to catch
    the false 500 on POST and navigate to the list instead of showing an error toast.
  • Added catchError in both resolvers (provisioning-entry.resolver.ts and
    provisioning-entry-entries.resolver.ts) to prevent the view page from
    crashing when the GET returns 500.
  • Suppressed the global error toast in error-handler.interceptor.ts for
    GET requests to /provisioningentries/{id}, following the same pattern
    used for client image 404s.

Note: The blank fields (Created By, Created On, Amount to be Reserved) on the
view page are a Fineract backend issue and have to be reported to the Fineract team.

Related issue

WEB-370

After Video:

Home.-.Google.Chrome.2026-03-04.01-18-17.mp4

Checklist

  • If you have multiple commits please combine them into one commit by squashing them.
  • Read and understood the contribution guidelines at web-app/.github/CONTRIBUTING.md.

Summary by CodeRabbit

Summary by CodeRabbit

  • Bug Fixes
    • Added resilient navigation after creating a provisioning entry to handle unexpected backend responses and avoid broken redirects.
    • Introduced fallback responses when loading provisioning entry data so the UI can recover gracefully from certain server errors.
    • Suppressed redundant internal-server error alerts for provisioning entry GET/POST operations to reduce noisy notifications.

@coderabbitai
Copy link

coderabbitai bot commented Mar 3, 2026

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'pre_merge_checks'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

Adds targeted error handling for provisioning-entry operations: the create component uses an object-based observer and handles HTTP 500 by navigating to the list; two resolvers return fallback payloads for 500 errors; the HTTP error interceptor suppresses 500 alerts for provisioning-entry GET/POST requests.

Changes

Cohort / File(s) Summary
Create Component
src/app/accounting/provisioning-entries/create-provisioning-entry/create-provisioning-entry.component.ts
Replaced subscribe callback with object-based observer (subscribe({ next, error })). On HTTP 500 error after create, navigate to provisioning-entry list; success navigation remains via response.resourceId. Removed a TODO and adjusted whitespace.
Resolvers
src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry-entries.resolver.ts, src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry.resolver.ts
Wrapped service calls with pipe(catchError(...)). For 500 errors, emit fallback objects ({ pageItems: [], error: true } and { id: provisioningEntryId, error: true } respectively); rethrow other errors. Added of, catchError, throwError imports.
HTTP Interceptor
src/app/core/http/error-handler.interceptor.ts
Suppresses generic 500 error alert for provisioning-entry GET/POST requests. Added TranslateService import/use for translated messages.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CreateComp as CreateComponent
    participant API as BackendAPI
    participant Router
    participant Interceptor as ErrorHandlerInterceptor
    participant ResolverEntries as EntriesResolver
    participant ResolverEntry as EntryResolver

    User->>CreateComp: submit(createPayload)
    CreateComp->>API: POST /provisioning-entries (via Interceptor)
    Note over Interceptor,API: Interceptor may suppress 500 alerts for provisioning-entry requests
    alt API returns 201 with resourceId
        API-->>CreateComp: 201 { resourceId }
        CreateComp->>Router: navigate(/provisioning-entry/:resourceId)
    else API returns 500 (no resourceId)
        API-->>CreateComp: 500 error
        CreateComp->>Router: navigate(/provisioning-entries)  // fallback on 500
    end

    User->>Router: open /provisioning-entry/:id
    Router->>ResolverEntry: resolve(id)
    ResolverEntry->>API: GET /provisioning-entries/:id (via Interceptor)
    alt API success
        API-->>ResolverEntry: 200 { entry }
        ResolverEntry-->>Router: resolved entry
    else API 500
        API-->>ResolverEntry: 500
        ResolverEntry-->>Router: { id, error: true }  // fallback
    end

    Router->>ResolverEntries: resolve entries page
    ResolverEntries->>API: GET /provisioning-entries (via Interceptor)
    alt API success
        API-->>ResolverEntries: 200 { pageItems }
        ResolverEntries-->>Router: resolved pageItems
    else API 500
        API-->>ResolverEntries: 500
        ResolverEntries-->>Router: { pageItems: [], error: true }  // fallback
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • alberto-art3ch
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically identifies the main change: handling Fineract 500 errors gracefully for provisioning entries. It directly corresponds to the primary objective and changes across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/app/accounting/provisioning-entries/create-provisioning-entry/create-provisioning-entry.component.ts (1)

82-92: Please replace any in the subscription handlers with concrete types.

The new handler signatures (response: any, error: any) reduce safety in this critical flow. Use a small response interface and HttpErrorResponse for the error branch.

Suggested typing update
+import { HttpErrorResponse } from '@angular/common/http';
+
+interface CreateProvisioningEntryResponse {
+  resourceId: number | string;
+}
...
-      next: (response: any) => {
+      next: (response: CreateProvisioningEntryResponse) => {
         this.router.navigate(
...
-      error: (error: any) => {
+      error: (error: HttpErrorResponse) => {
         if (error.status === 500) {
Based on learnings: In TypeScript files (e.g., src/app/.../*.ts), avoid using Observable as a project-wide pattern for API responses; introduce specific interfaces/types for response shapes and use proper typing instead of any.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/accounting/provisioning-entries/create-provisioning-entry/create-provisioning-entry.component.ts`
around lines 82 - 92, The subscription handlers in
create-provisioning-entry.component (the subscribe block with next: (response:
any) and error: (error: any)) use any — replace these with concrete types:
create a small interface (e.g., CreateProvisioningResponse { resourceId: string
| number }) and use it for the next handler signature (next: (response:
CreateProvisioningResponse) => ...); import and use Angular's HttpErrorResponse
for the error handler (error: (error: HttpErrorResponse) => ...); also update
the service method return type (e.g., createProvisioningEntry()) to
Observable<CreateProvisioningResponse> so the subscribe call is fully typed and
IDE/typechecker-safe.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry-entries.resolver.ts`:
- Around line 22-24: The resolver currently swallows all errors in the
getProvisioningEntryEntries observable by returning an empty payload in
catchError; change the catchError handler to only return of({ pageItems: [],
error: true }) when the HTTP error status is 500, and rethrow (propagate) other
errors so they can be handled upstream. Locate the pipe on
this.accountingService.getProvisioningEntryEntries(provisioningEntryId) and
replace the unconditional catchError with a conditional one that checks
err.status === 500 and returns the fallback, otherwise rethrows using
throwError(() => err) (or rethrowError equivalent) so non-500 failures are not
masked.

In
`@src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry.resolver.ts`:
- Around line 22-24: The catchError in the resolver's call to
accountingService.getProvisioningEntry is currently silencing all errors; change
it so only HTTP 500 responses are converted to the fallback object ({ id:
provisioningEntryId, error: true }) and all other errors are rethrown. Update
the catchError callback in the method that calls getProvisioningEntry (the
resolver function in provisioning-entry.resolver.ts) to inspect the error (e.g.,
err.status), return of({ id: provisioningEntryId, error: true }) when status ===
500, and rethrow other errors as an observable error (use RxJS throwError(() =>
err) or rethrow the error) so authorization/404/network errors propagate.

In `@src/app/core/http/error-handler.interceptor.ts`:
- Around line 88-95: The interceptor currently only suppresses alerts for GET
requests to provisioning entries; extend that logic to also suppress POST create
calls so the global alertService.alert is not shown for POST
/provisioningentries. Modify the check around request.url/request.method
(currently in the isProvisioningEntryGet variable) to detect either a GET to
'/provisioningentries/' or a POST to the collection endpoint (e.g.,
url.endsWith('/provisioningentries') && request.method === 'POST'), and use that
combined boolean to skip calling this.alertService.alert in
error-handler.interceptor.ts.

---

Nitpick comments:
In
`@src/app/accounting/provisioning-entries/create-provisioning-entry/create-provisioning-entry.component.ts`:
- Around line 82-92: The subscription handlers in
create-provisioning-entry.component (the subscribe block with next: (response:
any) and error: (error: any)) use any — replace these with concrete types:
create a small interface (e.g., CreateProvisioningResponse { resourceId: string
| number }) and use it for the next handler signature (next: (response:
CreateProvisioningResponse) => ...); import and use Angular's HttpErrorResponse
for the error handler (error: (error: HttpErrorResponse) => ...); also update
the service method return type (e.g., createProvisioningEntry()) to
Observable<CreateProvisioningResponse> so the subscribe call is fully typed and
IDE/typechecker-safe.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8989b78 and 6052d17.

📒 Files selected for processing (4)
  • src/app/accounting/provisioning-entries/create-provisioning-entry/create-provisioning-entry.component.ts
  • src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry-entries.resolver.ts
  • src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry.resolver.ts
  • src/app/core/http/error-handler.interceptor.ts

@YousufFFFF YousufFFFF force-pushed the fix-provisioning-entry-error-handling branch from 6052d17 to 2766e75 Compare March 3, 2026 20:19
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry-entries.resolver.ts (2)

20-29: Add proper typing to the error handler and return type.

The HTTP 500 scoping is now correctly in place. However, to improve type safety per project conventions:

  1. Type the error parameter as HttpErrorResponse to catch type mismatches at compile time.
  2. Replace Observable<any> with a specific interface for the response shape.

Based on learnings: "avoid using Observable as a project-wide pattern for API responses... introduce specific interfaces/types for the response shapes."

♻️ Proposed typing improvements
+import { HttpErrorResponse } from '@angular/common/http';
+
+interface ProvisioningEntryEntriesResponse {
+  pageItems: any[];
+  error?: boolean;
+}
+
 `@Injectable`()
 export class ProvisioningEntryEntriesResolver {
   private accountingService = inject(AccountingService);

-  resolve(route: ActivatedRouteSnapshot): Observable<any> {
+  resolve(route: ActivatedRouteSnapshot): Observable<ProvisioningEntryEntriesResponse> {
     const provisioningEntryId = route.paramMap.get('id');
     return this.accountingService.getProvisioningEntryEntries(provisioningEntryId).pipe(
-      catchError((error) => {
+      catchError((error: HttpErrorResponse) => {
         if (error.status === 500) {
           return of({ pageItems: [], error: true });
         }
         return throwError(() => error);
       })
     );
   }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry-entries.resolver.ts`
around lines 20 - 29, The resolver uses Observable<any> and an untyped error
handler; update the resolve method signature to return
Observable<ProvisioningEntryEntriesResponse> (define interface
ProvisioningEntryEntriesResponse { pageItems: YourItemType[]; error?: boolean;
... }), update any related service method getProvisioningEntryEntries to return
Observable<ProvisioningEntryEntriesResponse>, and type the catchError parameter
as (error: HttpErrorResponse) => Observable<ProvisioningEntryEntriesResponse>;
keep the same 500 branch returning of({ pageItems: [], error: true }) but ensure
the returned object conforms to the new interface and import HttpErrorResponse
from `@angular/common/http`.

12-13: Consider consolidating rxjs imports.

Both import lines pull from 'rxjs' and can be merged into a single statement for cleaner code.

♻️ Proposed consolidation
-import { Observable, of } from 'rxjs';
-import { catchError, throwError } from 'rxjs';
+import { Observable, of, catchError, throwError } from 'rxjs';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry-entries.resolver.ts`
around lines 12 - 13, Consolidate the duplicate rxjs imports in
provisioning-entry-entries.resolver.ts by replacing the two separate import
statements with a single import that includes Observable, of, catchError, and
throwError (i.e., import { Observable, of, catchError, throwError } from
'rxjs';) so the symbols Observable, of, catchError, and throwError are all
imported from the same statement.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry-entries.resolver.ts`:
- Around line 20-29: The resolver uses Observable<any> and an untyped error
handler; update the resolve method signature to return
Observable<ProvisioningEntryEntriesResponse> (define interface
ProvisioningEntryEntriesResponse { pageItems: YourItemType[]; error?: boolean;
... }), update any related service method getProvisioningEntryEntries to return
Observable<ProvisioningEntryEntriesResponse>, and type the catchError parameter
as (error: HttpErrorResponse) => Observable<ProvisioningEntryEntriesResponse>;
keep the same 500 branch returning of({ pageItems: [], error: true }) but ensure
the returned object conforms to the new interface and import HttpErrorResponse
from `@angular/common/http`.
- Around line 12-13: Consolidate the duplicate rxjs imports in
provisioning-entry-entries.resolver.ts by replacing the two separate import
statements with a single import that includes Observable, of, catchError, and
throwError (i.e., import { Observable, of, catchError, throwError } from
'rxjs';) so the symbols Observable, of, catchError, and throwError are all
imported from the same statement.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6052d17 and 2766e75.

📒 Files selected for processing (4)
  • src/app/accounting/provisioning-entries/create-provisioning-entry/create-provisioning-entry.component.ts
  • src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry-entries.resolver.ts
  • src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry.resolver.ts
  • src/app/core/http/error-handler.interceptor.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/app/accounting/provisioning-entries/create-provisioning-entry/create-provisioning-entry.component.ts
  • src/app/accounting/provisioning-entries/view-provisioning-entry/provisioning-entry.resolver.ts
  • src/app/core/http/error-handler.interceptor.ts

@YousufFFFF
Copy link
Member Author

Hi @IOhacker!
I have resolved the bot's comments
Also I have found an issue related to Fineract (I have mentioned the details on slack)
Appreciate your review!

message: 'Internal Server Error. Please try again later.'
});
const isProvisioningEntryGet =
request.url.includes('/provisioningentries') && (request.method === 'GET' || request.method === 'POST');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this piece of code reduce the possibility to catch the error in another endpoints or methods

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right to flag this!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check is intentionally scoped very narrowly, it only suppresses the toast for requests to /provisioningentries/ with GET or POST methods.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All other endpoints and methods will still trigger the global error toast as normal.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I think isClientImage404 uses this same pattern which is already in the codebase

@YousufFFFF
Copy link
Member Author

Hi @IOhacker,
Need your guidance here for further changes!

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.

2 participants