Skip to content

MPDX-10133 Stop error link crash that left pages stuck loading - #2127

Merged
frett merged 3 commits into
mainfrom
mpdx-10133-error-link-non-array
Oct 7, 2026
Merged

frett merged 3 commits into
mainfrom
mpdx-10133-error-link-non-array

Conversation

@frett

@frett frett commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

Description

MPDX-10133. Related backend fix: MPDX-10132 (CruGlobal/mpdx_api#3678).

  • The global Apollo error link threw graphQLErrors.forEach is not a function when a failed response's errors was an object or string instead of an array. Apollo passes that value through unchecked, and because the throw happens inside its error callback, the error never reached the query, so it stayed loading forever (the Staff Expense Report skeletons in HS-1776512).
  • The link now only walks graphQLErrors when it is an array. Network errors are still shown in the snackbar and reported to Datadog as before.
  • The Staff Expense Report now treats a failed Hcm query as a load error. It shows the existing "could not be loaded" alert instead of loading the report with the wrong fund types and no salary split, and Try Again refetches Hcm (the report then loads on its own).

Note: the API's own 500 for /graphql returns errors as an array, which was already handled. The Datadog issue was first seen on 8/24, before the Hcm 500s started on 10/5, so something else is sending the non-array shape. This change handles any shape, but the source is still unknown.

Testing

  • Unit tests: client.test.ts covers object, string and array errors on a network error; StaffExpenseReport.test.tsx covers the Hcm failure alert and Try Again recovery.
  • Manually: on the Staff Expense Report, make the Hcm query fail (e.g. block it in dev tools or use a user hit by MPDX-10132 before the backend fix) and check that the error alert shows instead of skeletons, and that Try Again loads the report once Hcm succeeds.

Checklist:

  • I have given my PR a title with the format "MPDX-(JIRA#) (summary sentence max 80 chars)"
  • I have applied the appropriate labels (Add the label "Preview" to automatically create a preview environment)
  • I have run the Claude Code /quality:agent-review command locally and fixed any relevant suggestions
  • I have requested a review from another person on the project
  • I have tested my changes in preview or in staging
  • I have cleaned up my commit history

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Bundle sizes [mpdx-react]

Compared against 06ca668

No significant changes found

@frett
frett marked this pull request as ready for review October 7, 2026 20:01
@frett

frett commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 agent-review · ✅ no blockers · risk CRITICAL
advisory rollout · 8 agents run (Security, Architecture, Data Integrity, Testing, Standards, Financial, API Contracts, UX) · full re-review (the previously reviewed head was rewritten by a force-push)

BLOCKERS — fix or dismiss to pass

✅ No blockers.

OTHER FINDINGS (5)

  • #1 · 5/10 · src/components/Reports/StaffExpenseReport/StaffExpenseReport.test.tsx:567 — expect(calls.report).toBe(0) can never fail: calls.report only increments inside failCallsWhen, and this test passes no failReportCall, so it does not prove the report query is skipped when HCM errors. — ✅ fixed in 4dc00d0
  • #2 · 4/10 · src/lib/apollo/client.ts:45 — The non-array graphQLErrors guard is only in the browser error link; the SSR error link in src/lib/apollo/ssrClient.ts still calls graphQLErrors.map(...) behind a truthiness check, so a string or object errors throws there the same way. — ✅ fixed in 9b409f1
  • #3 · 4/10 · src/components/Reports/StaffExpenseReport/StaffExpenseReport.tsx:164 — Every Hcm error now shows the generic "report could not be loaded" alert, but HCM-backed pages already render HcmUnavailableAlert (heavy-load message) for HCM_UNAVAILABLE, so this page says something different when HCM is overloaded. — 🚫 dismissed by @frett [intentional]: it's no longer possible to get an HCM_UNAVAILABLE error on the Staff Expense Report except in an extreme edge case that isn't worth having special logic for
  • #4 · 3/10 · src/components/Reports/StaffExpenseReport/StaffExpenseReport.tsx:422 — The supervisor view now hides the account name on an Hcm error too (loadError), but the new Hcm-failure tests only cover the non-supervisor view. (testing)
  • #5 · 2/10 · src/lib/apollo/client.test.ts:30 — The non-array tests don't assert that only the one network-error snackbar fires (no per-error toast). (testing)
🔧 Fix suggestions (3)

#3 — Use the existing HCM-unavailable alert: StaffExpenseReport.tsx:164

-              {loadError ? (
+              {isHcmUnavailableError(hcmError) ? (
+                <HcmUnavailableAlert refetch={refetchHcm} />
+              ) : loadError ? (

#4 — Add a supervisor-view test with failHcmCall={everyCall} and assert account-info is absent.

#5 — Tighten the snackbar assertion: client.test.ts

+      expect(snackNotifications.error).toHaveBeenCalledTimes(1);

No fix scripts were generated; apply by hand.

📦 Dependency impact

Blast radius: 138 files (not truncated).

Changed file Direct dependents
src/lib/apollo/ssrClient.ts pages/accountLists.page.tsx, pages/accountLists/[accountListId].page.tsx, pages/api/auth/[...nextauth].page.ts, pages/api/utils/pagePropsHelpers.ts, pages/setup/account.page.tsx (+4 tests)
src/lib/apollo/client.ts pages/_app.page.tsx
src/components/Reports/StaffExpenseReport/StaffExpenseReport.tsx pages/accountLists/[accountListId]/reports/staffExpense/index.page.tsx

The large blast radius comes from pagePropsHelpers.ts, which many pages use for getServerSideProps. The SSR change only affects how a failed response is logged.

📊 Review detail & stats

Generated: 2026-10-07 · Day: Wednesday · Files changed: 7 (+362 -178 lines)
Risk score: 36 — CRITICAL · Required reviewer: senior maintainer

Risk factors detected: core infrastructure scope (×2 multiplier) on both Apollo error links (src/lib/apollo/**); .claude/** change (review feedback store); unmatched path: .claude/review/learnings/feedback.jsonl.

Deterministic evidence:

⚠️ routing degraded — ran on the default model

Agent summary (bands: Critical 9-10 · High 7-8 · Important 5-6 · Suggestions 3-4):

Agent Critical High Important Suggestions Confidence
Security Review Agent 0 0 0 0 H
Architecture Review Agent 0 0 0 1 H
Data Integrity Review Agent 0 0 0 0 H
Testing Review Agent 0 0 0 1 (+1 at 2/10) M
Standards Review Agent 0 0 0 0 H
Financial Review Agent 0 0 0 0 H
API Contracts Review Agent 0 0 0 0 H
UX Review Agent 0 0 0 0 M
Total 0 0 0 2 -

Per-agent perspectives on blockers: none (no blockers).

Open question raised by agents:

  • Architecture: with cache-and-network, can useHcmQuery return cached hcmData together with a fresh hcmError (a refetch that fails after an earlier success)? If so, the report is hidden even though usable HCM data is in hand.

Review quality:

  • Average agent confidence: High · Consensus rate: 0% (3 singletons, no overlap) · Review time: ~10 minutes
  • Findings suppressed by approved learnings: 0
  • Debate rounds skipped: no blockers to cross-examine.
💬 How to act on this review

Every finding above is numbered. Severity ≥ 7 findings carry a checkbox and must each be fixed or
dismissed
before this review counts as passed; lower severities are advisory. Interact from a
PR comment — @claude fix 1, 3 · @claude dismiss 2 [false-positive]: <one-line reason>
(a reason code and explanation are required) — or locally with /agent-review:address. Valid
codes: false-positive, intentional, pre-existing, deferred, duplicate,
insufficient-evidence, other.

  • @claude fix 1, 3, 5 — AI applies those fixes on this branch and checks them off
  • @claude dismiss 2 [intentional]: matches legacy import behavior — checks it off with your
    reason; repeated dismissals of the same finding class teach the review to stop raising it
  • @claude fix 1, 3; dismiss 2 [false-positive]: guarded by the caller — mixed operations use a
    semicolon between clauses

Or locally: /agent-review:address pulls this ledger into a Claude Code session.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Auto-approved: the posted agent-review report covers the current head, passes with no open blockers, and the change is reversible.

Apollo passes a failed response's `errors` to the error link unchecked.
When it was an object or string, `graphQLErrors.forEach` threw inside
Apollo's error callback, so the error never reached the query and pages
like the Staff Expense Report stayed on their loading skeletons. The
link now only walks `graphQLErrors` when it is an array; network errors
are still toasted and reported.

The Staff Expense Report also treats a failed Hcm query as a load error:
it shows the existing alert instead of loading the report with the wrong
fund types and no salary split, and Try Again refetches Hcm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frett
frett force-pushed the mpdx-10133-error-link-non-array branch 2 times, most recently from 9e9cdff to 5c2422f Compare October 7, 2026 21:17

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Auto-approved: the posted agent-review report covers the current head, passes with no open blockers, and the change is reversible.

frett and others added 2 commits October 7, 2026 15:42
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The server-side error link had the same problem as the browser one:
Apollo passes a failed response's `errors` through unchecked, and
calling `.map` on an object or string threw inside the link, so the
query never settled and getServerSideProps hung. Only walk the errors
when they are an array; the network error is still sent to Rollbar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frett
frett force-pushed the mpdx-10133-error-link-non-array branch from 5c2422f to 9b409f1 Compare October 7, 2026 21:42
@frett
frett merged commit b4eb851 into main Oct 7, 2026
42 of 44 checks passed
@frett
frett deleted the mpdx-10133-error-link-non-array branch October 7, 2026 22:03
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