You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Due for payment 2026-06-09] [$250] [Sentry: APP-AZ6] TypeError: undefined is not an object (evaluating 't.reportID') in LHNOptionsList renderItem #91226
item passed to LHNOptionsList's renderItem is undefined during a re-render — possibly an off-by-one or stale-index access in @shopify/flash-list's ViewHolder when the underlying data shrinks before the recycler view rebuilds. Could also be a transient empty slot returned by the data source while a report is being optimistically deleted.
Safe guard: defensively bail out when item == null in LHNOptionsList.tsx's renderItem:
That avoids the crash regardless of root cause and lets us instrument what condition caused item to be undefined.
Reproduction
Unknown — reproductions in Sentry are tied to specific accounts viewing /r/:reportID. The crash happens during concurrent rendering recovery, which suggests a state-change race on the LHN list.
Related
Sibling Sentry IDs (if any): none identified
Prior GH issues: closest neighbour is closed App#84349 (childReportID, different code path)
@shopify/flash-list's ViewHolderCollection maintains an internal renderStack — a map of {reactKey → index} entries tracking which ViewHolders are mounted and at which data indices. When the data array shrinks (e.g., reports are removed from the LHN due to optimistic deletions, policy changes, or filter changes), the renderStack can still hold stale indices from the previous larger array. During concurrent rendering recovery on web, data[index] returns undefined for these out-of-bounds indices, which is passed directly to renderItem without any bounds check.
The data source itself is clean — useSidebarOrderedReports uses .filter(Boolean) so the array never contains undefined entries. The issue is purely a stale-index race in FlashList's recycler.
What changes do you think we should make in order to solve the problem?
Add a defensive null guard at the top of renderItem in LHNOptionsList.tsx:60-61 to bail out when item is undefined:
What alternative solutions did you explore? (Optional)
The upstream fix would be adding a bounds check in FlashList's ViewHolderCollection.tsx:179 (if (index >= data.length) return null). However, we don't control FlashList's release cycle, and the defensive guard in our code is safe, zero-cost, and immediately addresses the crash for all 1,689 affected users. Both fixes are complementary — the App-side guard is the right short-term solution regardless of whether an upstream fix lands.
Next Steps for Contributor+ team: Reply with @MelvinBot implement this to create a draft PR, @MelvinBot <your feedback> to refine this analysis, or explain why you are rejecting Melvin's proposal.
Please re-state the problem that we are trying to solve in this issue.
Some users crash on web while viewing a report route because the LHN FlashList row renderer is called with an undefined item, and LHNOptionsList immediately reads item.reportID.
What is the root cause of that problem?
LHNOptionsList assumes every renderItem invocation from FlashList has a defined report object:
That assumption is too strict for this virtualized list boundary. The data passed into LHNOptionsList is derived from useSidebarOrderedReports, which maps ordered report IDs through Onyx and filters out missing reports before exposing orderedReports:
So the likely failure mode is not a persistent undefined entry in orderedReports; it is a transient recycler/render race while the LHN data changes during report navigation or optimistic report deletion. FlashList can still call the existing renderItem with an empty item during that reconciliation window, and the first line of the renderer throws before the row can safely disappear.
What changes do you think we should make in order to solve the problem?
Add a defensive null guard at the start of LHNOptionsList's renderItem and return null when FlashList gives us no item. Concretely, change the callback return type to ReactElement | null, add if (!item) { return null; } before const reportID = item.reportID;, and update the local RenderItemProps type to allow item to be nullable/optional.
This keeps the fix at the virtualized-list boundary, avoids changing LHN ordering/cache logic, and prevents the crash regardless of whether the trigger is a stale FlashList index, a shrinking data array, or an optimistic report removal.
For coverage, add a focused unit test around LHNOptionsList's renderer behavior or the nearest existing LHN render test: render the list path with a mocked FlashList renderItem call where item is undefined and assert it returns null/does not throw. Existing normal-row rendering should continue to cover defined report items.
What alternative solutions did you explore? (Optional)
I considered changing useSidebarOrderedReports to filter harder, but it already filters missing Onyx reports when building orderedReports. That does not protect against FlashList invoking renderItem with a stale or empty item during recycling, so the crash guard belongs in LHNOptionsList.
I also considered deeper guards in OptionRowLHNData, but the crash happens before that component is rendered. Guarding at the first dereference is narrower and keeps invalid rows out of the row subtree entirely.
At draft time I found no strict duplicate proposal/comment on the issue. The closest related issue is #84349, which was another undefined-property crash during deletion, but it involved childReportID in a different flow.
Please re-state the problem that we are trying to solve in this issue.
On web, the app crashes with TypeError: undefined is not an object (evaluating 't.reportID'). The crash originates in the renderItem callback of the left-hand navigation list (LHNOptionsList): FlashList invokes renderItem with an item that is undefined, and the very first line of the callback reads item.reportID, which throws. This is a high-volume, web-only crash that has affected a large number of users.
What is the root cause of that problem?
There are two parts: why the read is unsafe, and why an undefined item reaches it specifically on web.
The first statement in renderItem reads item.reportID with no nullish check, even though the rest of the same callback already treats item as possibly missing (it uses item?.invoiceReceiver and item?.policyID further down). So the function is internally inconsistent — it guards item everywhere except the one line that crashes:
The crash is web-only, and the only web-specific behavior in this component is the FlashList initialScrollIndex, which is set to a saved scroll index on web and left undefined on native:
Nothing ever re-validates that saved index against the current list length. The data passed to the list is the dynamic report list (optionListItems), whose size changes constantly — reports get archived/deleted, search and filter results change, priority mode is toggled, accounts are switched. When the list shrinks after an index was saved at a deeper scroll position, the saved index can be larger than the current data.length. When FlashList mounts (or re-mounts during a concurrent-rendering recovery) and honors that out-of-range initialScrollIndex, it looks up data[index], gets undefined, and hands that undefined to renderItem — where item.reportID throws. On native, initialScrollIndex is undefined, so FlashList never starts from an out-of-range row, which is exactly why the crash is web-only.
A compounding factor: in ScrollOffsetContextProvider, saveScrollOffset/getScrollOffset and saveScrollIndex/getScrollIndex all read and write the same map entry, scrollOffsetsRef.current[getKey(route)]. The pixel offset and the row index share one storage slot per route and overwrite each other, which makes the stored index even less trustworthy:
What changes do you think we should make in order to solve the problem?
Two changes — one defensive (stops the crash regardless of source) and one that removes the actual web-only trigger.
In LHNOptionsList's renderItem, bail out early when item is nullish: return null for that row before reading item.reportID. This makes the callback consistent with the optional chaining it already uses lower down and guarantees the crash cannot happen no matter which path produced an undefined item. Returning null simply renders an empty cell for that transient slot, which FlashList immediately reconciles away on the next render.
Stop feeding FlashList an out-of-range start index. At the initialScrollIndex prop, only pass the saved index when it is actually valid for the current data — i.e. when data is non-empty and the saved index is >= 0 and < data.length. Otherwise pass undefined so the list starts from the top instead of being asked to render a row that does not exist. This addresses the root cause directly: FlashList is never told to render a non-existent item in the first place, so the defensive guard in change Some initial fixes and code style updates #1 should rarely (if ever) need to fire on web.
Together these eliminate both the symptom (the unguarded read) and the cause (the stale, out-of-bounds web start index).
What alternative solutions did you explore? (Optional)
Clamp the saved index to data.length - 1 rather than dropping it. Rejected: when the list has shrunk a lot, snapping the user to the last remaining row is worse UX than starting at the top, and when the list is empty data.length - 1 is -1, which is itself invalid.
Give saveScrollIndex/getScrollIndex their own storage key in ScrollOffsetContextProvider, separate from the offset. This is a worthwhile cleanup of the shared-slot collision, but on its own it does not prevent an out-of-bounds index after the list shrinks, so the in-bounds validation in change Fix spaces #2 is still required. It can be done as a follow-up.
changed the title [-][Sentry: APP-AZ6] TypeError: undefined is not an object (evaluating 't.reportID') in LHNOptionsList renderItem[/-][+][$250] [Sentry: APP-AZ6] TypeError: undefined is not an object (evaluating 't.reportID') in LHNOptionsList renderItem[/+]on May 21, 2026
Please re-state the problem that we are trying to solve in this issue.
On web/desktop only, LHNOptionsList's FlashList renderItem crashes with TypeError: undefined is not an object (evaluating 't.reportID') because item is undefined. Sentry APP-AZ6 reports 1,689 affected users (≈110 in the last 14 days) since 2026-04-22 on route /r/:reportID. The list should render the row or skip it without crashing the sidebar.
What is the root cause of that problem?
Two issues compound — one explains the unsafe read, one explains why the crash is web-only.
renderItem is internally inconsistent. At src/components/LHNOptionsList/LHNOptionsList.tsx:59-74, the very first line reads item.reportID with no nullish check — yet a few lines below the same callback already treats item as possibly missing (item?.invoiceReceiver, item?.policyID). The committed data from useSidebarOrderedReports is filtered with .filter(Boolean) (useSidebarOrderedReports.tsx:286-291), so the array itself is clean — but FlashList can still hand renderItem an undefined slot from its recycler pool, and the first dereference throws before the row can no-op.
Web-only trigger: stale initialScrollIndex is not validated against data.length.LHNOptionsList.tsx:160 sets initialScrollIndex={isWeb ? getScrollIndex(route) : undefined}. The saved index is written by onScroll (line 116-126) as Math.floor(contentOffset.y / estimatedItemSize) and is never re-validated when the list later shrinks (priority-mode toggle, archive/delete, account switch, filter change). When FlashList mounts/remounts with an out-of-range initialScrollIndex, it reads data[index], gets undefined, and passes it to renderItem. Native passes undefined, so the crash is web-only — exactly matching Sentry's platform filter.
Compounding bug in ScrollOffsetContextProvider. Both saveScrollOffset and saveScrollIndex write to the same map entry scrollOffsetsRef.current[getKey(route)] (src/components/ScrollOffsetContextProvider.tsx:80-81 and :125-126). The pixel offset and the row index share one slot per route and overwrite each other on every scroll event, so getScrollIndex can return whatever the last writer happened to put there — pixel offsets read as indices into a much smaller array.
What changes do you think we should make in order to solve the problem?
Three changes — one defensive (stops the crash regardless of source), two that fix the actual web-only triggers.
Guard renderItem and keyExtractor in LHNOptionsList.tsx. Change the callback return type to ReactElement | null, and at the top of renderItem add if (!item) { return null; } before const reportID = item.reportID;. Update RenderItemProps['item'] in src/components/LHNOptionsList/types.ts to be optional. Harden keyExtractor at line 24 to (item, index) => report_${item?.reportID ?? unknown_${index}}`` so an undefined-slot pass cannot throw inside FlashList's key resolution either.
Clamp initialScrollIndex against current data.length in LHNOptionsList.tsx:160. Compute it once: const initialScrollIndex = useMemo(() => { if (!isWeb) return undefined; const saved = getScrollIndex(route); return typeof saved === 'number' && saved >= 0 && saved < data.length ? saved : undefined; }, [getScrollIndex, route, data.length]);. This removes the actual trigger that made the crash web-only and keeps the saved-scroll restore feature working in the common case (list size unchanged).
Split storage for offset and index in ScrollOffsetContextProvider.tsx. Use separate ref maps (e.g. scrollOffsetsRef and scrollIndexesRef) so saveScrollOffset/saveScrollIndex no longer clobber each other's entries. Update cleanStaleScrollOffsets and the priority-mode reset effect to clean both maps. This removes the silent corruption where getScrollIndex returns a pixel offset.
No backend or native changes — LHNOptionsList.tsx and ScrollOffsetContextProvider.tsx are shared web modules; the crash is reported only on web/desktop, matching the web-only initialScrollIndex path.
What alternative solutions did you explore? (Optional)
Defensive guard alone (Melvin/KJ21 / the original posted proposal): necessary but insufficient. It hides the symptom but leaves the actual web-only trigger (stale initialScrollIndex) in place — the list will still start at a wrong scroll position when the saved index is stale, and the corrupted shared-slot storage will continue to feed misleading values into a defensive return null. Users would see brief blank rows on every cold render of a shrunken list.
Hoisting the guard into OptionRowLHNData: rejected — the throw happens at the first dereference in renderItem, before OptionRowLHNData is reached.
Filter harder in useSidebarOrderedReports: rejected — it already uses .filter(Boolean); the undefined originates inside FlashList's recycler reading data[staleIndex], not from the upstream array.
Upstream fix in @shopify/flash-list (ViewHolderCollection.tsx bounds check): out of our release cycle; complementary, not a substitute.
Activity
MelvinBot commentedon May 21, 2026
Proposal
What is the root cause of that problem?
@shopify/flash-list'sViewHolderCollectionmaintains an internalrenderStack— a map of{reactKey → index}entries tracking which ViewHolders are mounted and at which data indices. When thedataarray shrinks (e.g., reports are removed from the LHN due to optimistic deletions, policy changes, or filter changes), therenderStackcan still hold stale indices from the previous larger array. During concurrent rendering recovery on web,data[index]returnsundefinedfor these out-of-bounds indices, which is passed directly torenderItemwithout any bounds check.The data source itself is clean —
useSidebarOrderedReportsuses.filter(Boolean)so the array never containsundefinedentries. The issue is purely a stale-index race in FlashList's recycler.What changes do you think we should make in order to solve the problem?
Add a defensive null guard at the top of
renderIteminLHNOptionsList.tsx:60-61to bail out whenitemisundefined:Also guard
keyExtractorsince it has the same vulnerability:What alternative solutions did you explore? (Optional)
The upstream fix would be adding a bounds check in FlashList's
ViewHolderCollection.tsx:179(if (index >= data.length) return null). However, we don't control FlashList's release cycle, and the defensive guard in our code is safe, zero-cost, and immediately addresses the crash for all 1,689 affected users. Both fixes are complementary — the App-side guard is the right short-term solution regardless of whether an upstream fix lands.Next Steps for Contributor+ team: Reply with
@MelvinBot implement thisto create a draft PR,@MelvinBot <your feedback>to refine this analysis, or explain why you are rejecting Melvin's proposal.melvin-bot commentedon May 21, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @gijoe0295 (
External)KJ21-ENG commentedon May 21, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
Some users crash on web while viewing a report route because the LHN FlashList row renderer is called with an undefined
item, andLHNOptionsListimmediately readsitem.reportID.What is the root cause of that problem?
LHNOptionsListassumes everyrenderIteminvocation from FlashList has a defined report object:App/src/components/LHNOptionsList/LHNOptionsList.tsx
Lines 59 to 64 in eaaffe3
That assumption is too strict for this virtualized list boundary. The data passed into
LHNOptionsListis derived fromuseSidebarOrderedReports, which maps ordered report IDs through Onyx and filters out missing reports before exposingorderedReports:App/src/hooks/useSidebarOrderedReports.tsx
Lines 286 to 295 in eaaffe3
So the likely failure mode is not a persistent undefined entry in
orderedReports; it is a transient recycler/render race while the LHN data changes during report navigation or optimistic report deletion. FlashList can still call the existingrenderItemwith an empty item during that reconciliation window, and the first line of the renderer throws before the row can safely disappear.What changes do you think we should make in order to solve the problem?
Add a defensive null guard at the start of
LHNOptionsList'srenderItemand returnnullwhen FlashList gives us no item. Concretely, change the callback return type toReactElement | null, addif (!item) { return null; }beforeconst reportID = item.reportID;, and update the localRenderItemPropstype to allowitemto be nullable/optional.This keeps the fix at the virtualized-list boundary, avoids changing LHN ordering/cache logic, and prevents the crash regardless of whether the trigger is a stale FlashList index, a shrinking data array, or an optimistic report removal.
For coverage, add a focused unit test around
LHNOptionsList's renderer behavior or the nearest existing LHN render test: render the list path with a mocked FlashListrenderItemcall whereitemis undefined and assert it returnsnull/does not throw. Existing normal-row rendering should continue to cover defined report items.What alternative solutions did you explore? (Optional)
I considered changing
useSidebarOrderedReportsto filter harder, but it already filters missing Onyx reports when buildingorderedReports. That does not protect against FlashList invokingrenderItemwith a stale or empty item during recycling, so the crash guard belongs inLHNOptionsList.I also considered deeper guards in
OptionRowLHNData, but the crash happens before that component is rendered. Guarding at the first dereference is narrower and keeps invalid rows out of the row subtree entirely.At draft time I found no strict duplicate proposal/comment on the issue. The closest related issue is #84349, which was another undefined-property crash during deletion, but it involved
childReportIDin a different flow.wildan-m commentedon May 21, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On web, the app crashes with
TypeError: undefined is not an object (evaluating 't.reportID'). The crash originates in therenderItemcallback of the left-hand navigation list (LHNOptionsList): FlashList invokesrenderItemwith anitemthat isundefined, and the very first line of the callback readsitem.reportID, which throws. This is a high-volume, web-only crash that has affected a large number of users.What is the root cause of that problem?
There are two parts: why the read is unsafe, and why an
undefineditem reaches it specifically on web.renderItemreadsitem.reportIDwith no nullish check, even though the rest of the same callback already treatsitemas possibly missing (it usesitem?.invoiceReceiveranditem?.policyIDfurther down). So the function is internally inconsistent — it guardsitemeverywhere except the one line that crashes:App/src/components/LHNOptionsList/LHNOptionsList.tsx
Lines 58 to 74 in ed3aefa
initialScrollIndex, which is set to a saved scroll index on web and leftundefinedon native:App/src/components/LHNOptionsList/LHNOptionsList.tsx
Lines 160 to 166 in ed3aefa
getScrollIndex(route)returns an index that was saved earlier fromonScrollasMath.floor(contentOffset.y / estimatedItemSize):App/src/components/LHNOptionsList/LHNOptionsList.tsx
Lines 116 to 126 in ed3aefa
Nothing ever re-validates that saved index against the current list length. The
datapassed to the list is the dynamic report list (optionListItems), whose size changes constantly — reports get archived/deleted, search and filter results change, priority mode is toggled, accounts are switched. When the list shrinks after an index was saved at a deeper scroll position, the saved index can be larger than the currentdata.length. When FlashList mounts (or re-mounts during a concurrent-rendering recovery) and honors that out-of-rangeinitialScrollIndex, it looks updata[index], getsundefined, and hands thatundefinedtorenderItem— whereitem.reportIDthrows. On native,initialScrollIndexisundefined, so FlashList never starts from an out-of-range row, which is exactly why the crash is web-only.A compounding factor: in
ScrollOffsetContextProvider,saveScrollOffset/getScrollOffsetandsaveScrollIndex/getScrollIndexall read and write the same map entry,scrollOffsetsRef.current[getKey(route)]. The pixel offset and the row index share one storage slot per route and overwrite each other, which makes the stored index even less trustworthy:App/src/components/ScrollOffsetContextProvider.tsx
Lines 78 to 88 in ed3aefa
App/src/components/ScrollOffsetContextProvider.tsx
Lines 125 to 133 in ed3aefa
What changes do you think we should make in order to solve the problem?
Two changes — one defensive (stops the crash regardless of source) and one that removes the actual web-only trigger.
In
LHNOptionsList'srenderItem, bail out early whenitemis nullish: returnnullfor that row before readingitem.reportID. This makes the callback consistent with the optional chaining it already uses lower down and guarantees the crash cannot happen no matter which path produced an undefined item. Returningnullsimply renders an empty cell for that transient slot, which FlashList immediately reconciles away on the next render.Stop feeding FlashList an out-of-range start index. At the
initialScrollIndexprop, only pass the saved index when it is actually valid for the current data — i.e. whendatais non-empty and the saved index is>= 0and< data.length. Otherwise passundefinedso the list starts from the top instead of being asked to render a row that does not exist. This addresses the root cause directly: FlashList is never told to render a non-existent item in the first place, so the defensive guard in change Some initial fixes and code style updates #1 should rarely (if ever) need to fire on web.Together these eliminate both the symptom (the unguarded read) and the cause (the stale, out-of-bounds web start index).
Compare branch: https://github.com/Expensify/App/compare/main...wildan-m:App:wildan/91226-lhn-options-list-undefined-item?expand=1
What alternative solutions did you explore? (Optional)
data.length - 1rather than dropping it. Rejected: when the list has shrunk a lot, snapping the user to the last remaining row is worse UX than starting at the top, and when the list is emptydata.length - 1is-1, which is itself invalid.saveScrollIndex/getScrollIndextheir own storage key inScrollOffsetContextProvider, separate from the offset. This is a worthwhile cleanup of the shared-slot collision, but on its own it does not prevent an out-of-bounds index after the list shrinks, so the in-bounds validation in change Fix spaces #2 is still required. It can be done as a follow-up.[-][Sentry: APP-AZ6] TypeError: undefined is not an object (evaluating 't.reportID') in LHNOptionsList renderItem[/-][+][$250] [Sentry: APP-AZ6] TypeError: undefined is not an object (evaluating 't.reportID') in LHNOptionsList renderItem[/+]melvin-bot commentedon May 21, 2026
Job added to Upwork: https://www.upwork.com/jobs/~022057380356069354523
aswin-s commentedon May 21, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On web/desktop only,
LHNOptionsList's FlashListrenderItemcrashes withTypeError: undefined is not an object (evaluating 't.reportID')becauseitemisundefined. Sentry APP-AZ6 reports 1,689 affected users (≈110 in the last 14 days) since 2026-04-22 on route/r/:reportID. The list should render the row or skip it without crashing the sidebar.What is the root cause of that problem?
Two issues compound — one explains the unsafe read, one explains why the crash is web-only.
renderItemis internally inconsistent. Atsrc/components/LHNOptionsList/LHNOptionsList.tsx:59-74, the very first line readsitem.reportIDwith no nullish check — yet a few lines below the same callback already treatsitemas possibly missing (item?.invoiceReceiver,item?.policyID). The committeddatafromuseSidebarOrderedReportsis filtered with.filter(Boolean)(useSidebarOrderedReports.tsx:286-291), so the array itself is clean — but FlashList can still handrenderItemanundefinedslot from its recycler pool, and the first dereference throws before the row can no-op.Web-only trigger: stale
initialScrollIndexis not validated againstdata.length.LHNOptionsList.tsx:160setsinitialScrollIndex={isWeb ? getScrollIndex(route) : undefined}. The saved index is written byonScroll(line 116-126) asMath.floor(contentOffset.y / estimatedItemSize)and is never re-validated when the list later shrinks (priority-mode toggle, archive/delete, account switch, filter change). When FlashList mounts/remounts with an out-of-rangeinitialScrollIndex, it readsdata[index], getsundefined, and passes it torenderItem. Native passesundefined, so the crash is web-only — exactly matching Sentry's platform filter.Compounding bug in
ScrollOffsetContextProvider. BothsaveScrollOffsetandsaveScrollIndexwrite to the same map entryscrollOffsetsRef.current[getKey(route)](src/components/ScrollOffsetContextProvider.tsx:80-81and:125-126). The pixel offset and the row index share one slot per route and overwrite each other on every scroll event, sogetScrollIndexcan return whatever the last writer happened to put there — pixel offsets read as indices into a much smaller array.What changes do you think we should make in order to solve the problem?
Three changes — one defensive (stops the crash regardless of source), two that fix the actual web-only triggers.
Guard
renderItemandkeyExtractorinLHNOptionsList.tsx. Change the callback return type toReactElement | null, and at the top ofrenderItemaddif (!item) { return null; }beforeconst reportID = item.reportID;. UpdateRenderItemProps['item']insrc/components/LHNOptionsList/types.tsto be optional. HardenkeyExtractorat line 24 to(item, index) =>report_${item?.reportID ??unknown_${index}}`` so an undefined-slot pass cannot throw inside FlashList's key resolution either.Clamp
initialScrollIndexagainst currentdata.lengthinLHNOptionsList.tsx:160. Compute it once:const initialScrollIndex = useMemo(() => { if (!isWeb) return undefined; const saved = getScrollIndex(route); return typeof saved === 'number' && saved >= 0 && saved < data.length ? saved : undefined; }, [getScrollIndex, route, data.length]);. This removes the actual trigger that made the crash web-only and keeps the saved-scroll restore feature working in the common case (list size unchanged).Split storage for offset and index in
ScrollOffsetContextProvider.tsx. Use separate ref maps (e.g.scrollOffsetsRefandscrollIndexesRef) sosaveScrollOffset/saveScrollIndexno longer clobber each other's entries. UpdatecleanStaleScrollOffsetsand the priority-mode reset effect to clean both maps. This removes the silent corruption wheregetScrollIndexreturns a pixel offset.No backend or native changes —
LHNOptionsList.tsxandScrollOffsetContextProvider.tsxare shared web modules; the crash is reported only on web/desktop, matching the web-onlyinitialScrollIndexpath.What alternative solutions did you explore? (Optional)
initialScrollIndex) in place — the list will still start at a wrong scroll position when the saved index is stale, and the corrupted shared-slot storage will continue to feed misleading values into a defensivereturn null. Users would see brief blank rows on every cold render of a shrunken list.OptionRowLHNData: rejected — the throw happens at the first dereference inrenderItem, beforeOptionRowLHNDatais reached.useSidebarOrderedReports: rejected — it already uses.filter(Boolean); theundefinedoriginates inside FlashList's recycler readingdata[staleIndex], not from the upstream array.@shopify/flash-list(ViewHolderCollection.tsxbounds check): out of our release cycle; complementary, not a substitute.38 remaining items
melvin-bot commentedon Jun 12, 2026
@mallenexpensify Whoops! This issue is 2 days overdue. Let's get this updated quick!
gijoe0295 commentedon Jun 16, 2026
@mallenexpensify This is due
mallenexpensify commentedon Jun 16, 2026
Payment Summary
Contributor: @wildan-m paid $250 via Upwork
Contributor+: @gijoe0295 due $250 via NewDot
no tests needed.
JmillsExpensify commentedon Jun 16, 2026
$250 approved for @gijoe0295
mountiny commentedon Jul 2, 2026
Fresh Sentry numbers for APP-AZ6 (closed tracker — still seeing events):