Skip to content

Conversation

@MelvinBot
Copy link
Contributor

@MelvinBot MelvinBot commented Feb 12, 2026

Explanation of Change

Fixed Issues

$
PROPOSAL:

Tests

  • Verify that no errors appear in the JS console

Offline tests

QA Steps

// TODO: These must be filled out, or the issue title must include "[No QA]."

  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I verified there are no new alerts related to the canBeMissing param for useOnyx
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
      • If any non-english text was added/modified, I used JaimeGPT to get English > Spanish translation. I then posted it in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari

The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-QS-15268416
@MelvinBot MelvinBot requested a review from a team as a code owner February 12, 2026 08:54
@melvin-bot melvin-bot bot requested review from MarioExpensify and removed request for a team February 12, 2026 08:54
@melvin-bot
Copy link

melvin-bot bot commented Feb 12, 2026

@MarioExpensify Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

The Snyk auto-fix PR updated package.json to use
[email protected] but did not regenerate
package-lock.json, causing npm ci to fail in all CI checks.
@MelvinBot
Copy link
Contributor Author

Fixed the failing checks. All CI failures (TypeScript, ESLint, Prettier, Translation Dry Run, Spellcheck, etc.) had the same root cause: npm ci was failing because package-lock.json was out of sync with package.json.

The Snyk auto-fix updated react-native-google-places-autocomplete from 2.5.6 to 2.6.4 in package.json but did not regenerate package-lock.json. This caused three mismatches:

I regenerated package-lock.json and pushed the fix.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8e95219764

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

"react-native-gesture-handler": "2.28.0",
"react-native-get-random-values": "^1.11.0",
"react-native-google-places-autocomplete": "2.5.6",
"react-native-google-places-autocomplete": "2.6.4",

Choose a reason for hiding this comment

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

P1 Badge Update package-lock.json with this dependency change

This change bumps react-native-google-places-autocomplete in package.json but leaves package-lock.json pinned to 2.5.6 (package-lock.json:112), so the upgrade is not actually reproducible. In this repo, CI setup runs npm ci (.github/actions/composite/setupNode/action.yml:56), and npm ci requires the manifest and lockfile to be in sync (it errors: npm ci can only install packages when your package.json and package-lock.json ... are in sync), which can break installs on cache misses; on cache hits, the cache key is derived from package-lock.json (action.yml:35), so workers can keep reusing node_modules with the old vulnerable version.

Useful? React with 👍 / 👎.

@situchan
Copy link
Contributor

If this requires C+ testing, I can help

The patch was created for v2.5.6 to add React 19 support by removing
defaultProps and forwardRef usage. Version 2.6.4 already removes
defaultProps and uses destructured defaults, making this patch
unnecessary and incompatible with the new version.
@MelvinBot
Copy link
Contributor Author

Fixed the failing checks by removing the obsolete patch-package patch for react-native-google-places-autocomplete.

Root cause: The Snyk upgrade from v2.5.6 to v2.6.4 broke npm ci (lockfile mismatch) and patch-package (patch no longer applies). The lockfile was fixed in a previous commit, but the patch file was still targeting v2.5.6.

Why the patch is no longer needed: The patch added React 19 compatibility by removing defaultProps and forwardRef. Version 2.6.4 already removes defaultProps and uses destructured defaults inline, so the patch is obsolete and incompatible with the new source.

What was removed:

  • patches/react-native-google-places-autocomplete/react-native-google-places-autocomplete+2.5.6+001+react-19-support.patch
  • patches/react-native-google-places-autocomplete/details.md

@MelvinBot
Copy link
Contributor Author

The failing checks on the previous commit (4c3009d) were caused by a patch-package conflict: the PR upgraded react-native-google-places-autocomplete from 2.5.6 to 2.6.4, but the old patch file (react-native-google-places-autocomplete+2.5.6+001+react-19-support.patch) was still present. Since the patch was written for 2.5.6, it couldn't apply to the new 2.6.4 version, which broke npm install (postinstall hook) and cascaded into ESLint, TypeScript, Prettier, and Spellcheck failures.

The latest commit (896fff5 — "Remove obsolete react-native-google-places-autocomplete patch") already fixes this by deleting the obsolete patch file and its details.md. The currently running checks are passing — ESLint, Prettier, validate-patches, spellcheck, and Storybook tests have all completed successfully, with the remaining checks (typecheck, unit tests, builds) still in progress.

No further code changes should be needed.

…ete v2.6.4

The upgraded react-native-google-places-autocomplete package changed
the Point interface to require both lat/lng and latitude/longitude
properties. Updated recentWaypointsSelector to provide all four.
@MelvinBot MelvinBot requested a review from a team as a code owner February 12, 2026 09:18
@melvin-bot melvin-bot bot requested review from heyjennahay and removed request for a team February 12, 2026 09:18
@MelvinBot
Copy link
Contributor Author

Fixed the failing typecheck check.

Root cause: The upgrade of react-native-google-places-autocomplete from 2.5.6 to 2.6.4 changed the Point interface to require both lat/lng and latitude/longitude properties. The recentWaypointsSelector in IOURequestStepWaypoint.tsx was only providing lat/lng.

Fix: Added latitude and longitude properties to the geometry location object in recentWaypointsSelector, mapping them from the same waypoint lat/lng values.

@MelvinBot
Copy link
Contributor Author

The failing checks have already been fixed in the latest commit (71ad589). The previous failures were caused by two related issues from the react-native-google-places-autocomplete upgrade from 2.5.6 to 2.6.4:

  1. patch-package failure — The old patch file (react-native-google-places-autocomplete+2.5.6+001+react-19-support.patch) couldn't apply to v2.6.4. This patch was removed since v2.6.4 already includes React 19 support. This cascaded into ESLint and spellcheck failures because npm ci failed during setup.

  2. TypeScript error — The Point type in v2.6.4 now requires latitude/longitude properties in addition to lat/lng. The recentWaypointsSelector in IOURequestStepWaypoint.tsx was updated to provide all four properties.

The current CI run shows all completed checks passing (typecheck ✅, ESLint ✅, Prettier ✅, spellcheck ✅, validate-patches ✅, Storybook ✅, builds ✅). Tests and remaining builds are still in progress.

@codecov
Copy link

codecov bot commented Feb 12, 2026

Codecov Report

✅ Changes either increased or maintained existing code coverage, great job!

Files with missing lines Coverage Δ
.../pages/iou/request/step/IOURequestStepWaypoint.tsx 0.00% <0.00%> (ø)
... and 78 files with indirect coverage changes

@@ -48,6 +48,8 @@ function recentWaypointsSelector(waypoints: RecentWaypoint[] = []) {
location: {
lat: waypoint.lat ?? 0,
Copy link
Contributor

Choose a reason for hiding this comment

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

@MelvinBot do we still need the old lat/lng parameters? Or just the new latitude/longitude?

@MelvinBot
Copy link
Contributor Author

Both are needed. The Point type in react-native-google-places-autocomplete v2.6.4 defines all four properties as required:

interface Point {
  lat: number;
  lng: number;
  latitude: number;
  longitude: number;
}

Since TypeScript enforces this, omitting either pair would cause a type error. The PR correctly provides all four (lat, lng, latitude, longitude) to satisfy the updated type.

The rest of the codebase (e.g., AddressSearch/index.tsx) reads lat/lng from details.geometry.location, so both pairs need to remain populated.

@MelvinBot
Copy link
Contributor Author

The failing check is checklist (reviewerChecklist), which is unrelated to the PR's code changes.

Analysis: This check requires a reviewer to post a comment containing the Reviewer Checklist (from contributingGuides/REVIEWER_CHECKLIST.md) with all items checked off. It is triggered by pull_request_review events. Two reviews have been submitted (by chatgpt-codex-connector[bot] and MarioExpensify), but neither included the reviewer checklist — so the check fails with No PR Reviewer Checklist was found.

Evidence: All other checks pass (ESLint, typecheck, Prettier, tests, builds, verifySignedCommits, etc.). The failure is purely a process check, not a code issue.

Resolution: A reviewer needs to post the Reviewer Checklist as a PR comment with all items checked off. This will cause the checklist check to pass on re-run.

@MarioExpensify
Copy link
Contributor

@situchan yes, please test, review and fill in the checklist. Thank you!

Comment on lines +51 to +52
latitude: waypoint.lat ?? 0,
longitude: waypoint.lng ?? 0,
Copy link
Contributor

@situchan situchan Feb 12, 2026

Choose a reason for hiding this comment

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

This is to fix lint error. These props were added in this upstream PR. Not used anywhere in our app.
Old lat/lng parameters are still needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I investigated the full GooglePlacesAutocomplete.js source (v2.6.4) for all forward-reference / TDZ issues.

True TDZ violations (cause runtime ReferenceError): There are exactly 3, and the existing patch already fixes all of them:

Variable Referenced at Declared at Why it crashes Patch fix
_request Line 161 Line 466 useRef(_request) evaluates immediately Changed to useRef(null)
_disableRowLoaders Line 450 (dep array) Line 653 useCallback dep arrays evaluate immediately Moved declaration to ~line 348
_disableRowLoaders Line 629 (dep array) Line 653 Same as above Same move fixes both

_renderDescription and getCurrentLocation are NOT true TDZ violations. They are "soft" forward references — referenced only inside function bodies (like _onPress) that execute lazily from event handlers, not during render. By the time a user taps a row and _onPress fires, the entire component body has already executed and all const declarations are initialized.

Full list of soft forward references (safe, no runtime errors):

Referenced variable Referenced inside Ref lines Declared at
_renderDescription _onPress body 696, 704, 762, 768 837
hideListView _onPress body 670, 758, 767 795
_onBlur _onPress body 694, 770 821
debounceData _onChangeText body 782 1082

These 4 cases reference later-declared const functions, but only inside callback bodies that never run during render — they only run when triggered by user interaction or effects, at which point all declarations are initialized.

Bottom line: The current patch already covers all runtime TDZ crashes. The soft forward references are standard JavaScript and don't need reordering for correctness. That said, if you'd prefer to reorder them for code clarity/consistency, I can do that — just let me know.

Copy link
Contributor

Choose a reason for hiding this comment

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

if you'd prefer to reorder them for code clarity/consistency, I can do that — just let me know.

Please do that

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Updated the patch to reorder all forward-referenced declarations so they are declared before use:

Moved before _onPress:

  • _renderDescription (was in RENDER FUNCTIONS section)
  • hideListView (was after _handleChangeText)
  • isNewFocusInAutocompleteResultList (was after hideListView)
  • _onBlur (was after isNewFocusInAutocompleteResultList)
  • _onFocus (was after _onBlur)

Moved before _onChangeText:

  • debounceData (was in the EFFECTS section)

Commit: 4029453

@situchan
Copy link
Contributor

situchan commented Feb 12, 2026

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard.
  • I verified tests pass on all platforms & I tested again on:
    • Android: HybridApp
    • Android: mWeb Chrome
    • iOS: HybridApp
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • MacOS: Desktop
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified there are no new alerts related to the canBeMissing param for useOnyx
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • For any bug fix or new feature in this PR, I verified that sufficient unit tests are included to prevent regressions in this flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Android: HybridApp
Android: mWeb Chrome
iOS: HybridApp
iOS: mWeb Safari
MacOS: Chrome / Safari

@MelvinBot
Copy link
Contributor Author

The failing check is not related to the code changes in this PR.

Analysis: The checklist check requires a reviewer to post a comment containing a fully completed # Reviewer Checklist. No such comment exists on this PR yet, so the check fails with "No PR Reviewer Checklist was found."

How to fix: A reviewer needs to copy the Reviewer Checklist, paste it as a PR comment, and check off all items after reviewing the changes. This is not something that can be resolved with a code push.

All other checks (ESLint, typecheck, Prettier, tests, builds, signed commits, etc.) are passing.

@situchan
Copy link
Contributor

@MelvinBot if possible, can you add this change?

function recentWaypointsSelector(waypoints: RecentWaypoint[] = []) {

- function recentWaypointsSelector(waypoints: RecentWaypoint[] = []) {
+ function recentWaypointsSelector(waypoints: RecentWaypoint[] = []): PredefinedPlace[] {

Along with import type {PredefinedPlace} from '@components/AddressSearch/types';

@MelvinBot
Copy link
Contributor Author

Done — pushed 43db18c with both changes:

  1. Added import type {PredefinedPlace} from '@components/AddressSearch/types';
  2. Added explicit : PredefinedPlace[] return type to recentWaypointsSelector

@situchan
Copy link
Contributor

@MelvinBot app crashes on this line:

installHook.js:1 ReferenceError: Cannot access '_request' before initialization
at GooglePlacesAutocomplete (GooglePlacesAutocomplete.js:175:68)

Screen.Recording.2026-02-12.at.6.41.27.PM.mov

@MelvinBot
Copy link
Contributor Author

🔍 Crash Analysis

Summary: The app crashes at runtime because react-native-google-places-autocomplete v2.6.4 has a Temporal Dead Zone (TDZ) bug — _request is referenced before its declaration.

Root Cause: In GooglePlacesAutocomplete.js v2.6.4, line 161 does const requestRef = useRef(_request), but _request is declared with const on line 466 — 305 lines later. Since const bindings exist in the TDZ until their declaration is reached, accessing _request at line 161 throws ReferenceError: Cannot access '_request' before initialization. This was introduced by the v2.6.x refactor that added a requestRef pattern for stale-closure mitigation but placed the useRef() call before the function it references.

This bug did not exist in v2.5.6, which had no requestRef pattern and only referenced _request after its declaration.

Recommended Fix: Add a patch-package patch to change line 161 from:

const requestRef = useRef(_request);

to:

const requestRef = useRef(null);

This is safe because requestRef.current is already reassigned to _request on every render at line 1079 (requestRef.current = _request;), before the debounced function that uses it can ever be invoked.

There is no v2.6.5 or newer available on npm — v2.6.4 is the latest published version, and no upstream fix exists.

Detailed Investigation

Root Cause Analysis

The v2.6.x refactor (upstream PR #990) reorganized the component code into sections. The requestRef was placed in the "STATE & REFS" section near the top of the component function body:

// Line 161 - STATE & REFS section
const requestRef = useRef(_request);

But _request is defined much later in the "API REQUEST FUNCTIONS" section:

// Line 466 - API REQUEST FUNCTIONS section
const _request = (text) => {
    _abortRequests();
    // ...
};

JavaScript const declarations are hoisted (the binding is created at scope entry) but remain uninitialized until the declaration is evaluated. Accessing the binding before that point throws a ReferenceError.

Evidence Chain

  1. Component function body starts executing top-to-bottom
  2. Line 161: useRef(_request) — JavaScript tries to read _request
  3. _request is in the TDZ (declared at line 466 but not yet reached)
  4. ReferenceError: Cannot access '_request' before initialization is thrown
  5. Component never finishes mounting → app crashes

Why the patch is safe

The requestRef pattern was introduced to avoid stale closures in the debounced function:

// Line 1079 - runs on every render, AFTER _request is defined
requestRef.current = _request;

// Line 1082 - debounced function reads requestRef.current when invoked
const debounceData = useMemo(() => {
    return debounce((text) => requestRef.current(text), debounceMs);
}, [debounceMs]);

The initial value passed to useRef() only matters for the very first render, and requestRef.current is overwritten by _request at line 1079 before any user interaction could trigger debounceData. Setting the initial value to null is therefore safe.

Relevant Code

  • GooglePlacesAutocomplete.js:161 — TDZ violation: useRef(_request) before _request is declared
  • GooglePlacesAutocomplete.js:466_request const declaration
  • GooglePlacesAutocomplete.js:1079requestRef.current = _request (safe reassignment after declaration)

Next Steps: A patch-package patch is needed to fix this. Reply with @MelvinBot implement this to create a draft PR with the patch, or @MelvinBot <your feedback> to refine this analysis.

@MelvinBot
Copy link
Contributor Author

The failing check is unrelated to this PR's changes.

Failing check: Verify Android HybridApp builds on main

Error:

Execution failed for task ':react-native:packages:react-native:ReactAndroid:hermes-engine:configureCMakeRelease[arm64-v8a]'.
> [CXX1300] CMake '3.30.5' was not found in SDK, PATH, or by cmake.dir property.

Analysis: This is a CI infrastructure issue — the GitHub Actions runner is missing CMake version 3.30.5 required by the Hermes engine Android build. This PR only upgrades react-native-google-places-autocomplete from 2.5.6 to 2.6.4 and makes a minor change to IOURequestStepWaypoint.tsx. None of these changes affect the Android native build toolchain, CMake configuration, or Hermes engine.

Evidence:

  • The iOS HybridApp build (same workflow) passed successfully
  • All other checks passed (ESLint, typecheck, Prettier, tests, non-HybridApp Android builds)
  • The error occurs in the Hermes engine CMake configuration step, which is unrelated to the JS/npm dependency change in this PR

This likely needs to be resolved by updating the CI runner image to include CMake 3.30.5, or pinning the expected CMake version in the Android build configuration. Please reach out in #expensify-open-source for infrastructure support.

@situchan
Copy link
Contributor

Next Steps: A patch-package patch is needed to fix this.

@MelvinBot let's create patch in this PR

v2.6.4 has a bug where `useRef(_request)` references `_request` before
its const declaration, causing a ReferenceError at runtime. This patch
changes the initial value to `null`, which is safe because
`requestRef.current` is reassigned to `_request` on every render before
it can be invoked.

Co-authored-by: Situ Chandra Shil <[email protected]>
@MelvinBot
Copy link
Contributor Author

Created the patch-package patch in 7ded213.

What the patch does: Changes useRef(_request) to useRef(null) on line 161 of GooglePlacesAutocomplete.js, fixing the Temporal Dead Zone crash (ReferenceError: Cannot access '_request' before initialization).

Why it's safe: requestRef.current is reassigned to _request on every render at line 1079, before the debounced function that reads it can ever be invoked. The initial value passed to useRef() is effectively unused.

Files added:

  • patches/react-native-google-places-autocomplete/react-native-google-places-autocomplete+2.6.4+001+fix-tdz-crash.patch
  • patches/react-native-google-places-autocomplete/details.md

The patch was tested locally and applies cleanly via patch-package.

@situchan
Copy link
Contributor

App still crashes for me locally.

@MelvinBot can you generate adhoc build for testing?

@MelvinBot
Copy link
Contributor Author

I'm not able to trigger ad-hoc builds directly, but you can generate one yourself from the Actions tab:

  1. Go to Actions → testBuild
  2. Click "Run workflow"
  3. Set APP_PULL_REQUEST_URL to https://github.com/Expensify/App/pull/82233
  4. Check REVIEWED_CODE (required — confirms no malicious code)
  5. Select which platforms you need (Web / iOS / Android — all default to true)
  6. Click Run workflow

Once the build completes, download links will be posted as a comment on this PR.

Regarding the local crash — could you share the error/stack trace? That would help determine whether there's a runtime issue beyond the TypeScript fix that was already applied.

@MelvinBot
Copy link
Contributor Author

The failing checks have been analyzed:

  1. TypeScript Checks (typecheck) — This was failing because the upgrade from react-native-google-places-autocomplete v2.5.6 to v2.6.4 changed the Place type to require latitude and longitude fields in the Point interface, in addition to lat/lng. The fix in commit 43db18c (adding latitude/longitude to the recentWaypointsSelector and an explicit PredefinedPlace[] return type) resolved this. Typecheck is now passing.

  2. Verify Android HybridApp builds on main — This failed with Execution failed for task ':react-native:packages:react-native:ReactAndroid:hermes-engine:configureCMakeRelease[arm64-v8a]'. This is a CI infrastructure/build environment issue (CMake configuration for Hermes) and is unrelated to this PR, which only changes TypeScript/JS files and package.json. The current re-run is still in progress.

All other checks (ESLint, Prettier, spellcheck, all 8 test jobs, all app builds, validate-patches, verifySignedCommits) are passing.

@situchan
Copy link
Contributor

@MelvinBot your patch still doesn't fix the crash. Can you investigate more?

@situchan
Copy link
Contributor

@MarioExpensify can you please generate adhoc build?

@MelvinBot
Copy link
Contributor Author

🔍 Issue Analysis

Summary: The react-native-google-places-autocomplete v2.6.4 has multiple issues beyond the single TDZ fix already applied. The crash likely has more than one contributing cause.

Root Cause: The v2.6.4 rewrite introduced several Temporal Dead Zone (TDZ) issues and a new react-native-uuid dependency. The existing patch only fixes one of these issues.

Recommended Fix: The v2.6.4 library needs a more comprehensive patch — or the upgrade should be reconsidered, since the library appears semi-abandoned (upstream issue #978).

Issues Found

Issue 1 (Patched): useRef(_request) TDZ — Line 161
Already patched. _request is declared at line 466, referenced at line 161. The patch correctly changes useRef(_request)useRef(null).

Issue 2 (NOT Patched): _disableRowLoaders TDZ in dependency arrays — Lines 450, 629
_disableRowLoaders is declared with const at line 653, but referenced in useCallback dependency arrays at:

  • Line 450: _requestNearby's deps
  • Line 629: getCurrentLocation's deps

Babel's @babel/plugin-transform-block-scoping transforms constvar, so this won't throw a ReferenceError at runtime. However, the value is undefined on first render, which causes React hooks to see a dependency change every render. This can lead to infinite re-render loops or stale closures causing erratic behavior.

Issue 3: react-native-uuid default import — Line 4, 172
The library does import uuid from 'react-native-uuid' (ESM default import) on a CJS module that exports via exports.default = { ... }. While Metro's CJS interop should handle this via the __esModule flag, this is a new transitive dependency that didn't exist in v2.5.6 and could behave differently depending on Metro bundler version and configuration. If uuid.v4() (line 172, called inside useState) resolves incorrectly, it would crash immediately on component mount.

Diagnostic Steps

@situchan — could you share the crash stack trace? That would confirm which of these issues is the actual cause. In the meantime:

  1. Verify the patch applied: After npm install, check that line 161 of node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js shows useRef(null) and not useRef(_request). If it still shows _request, the patch didn't apply.

  2. Check if it's the uuid: Add a temporary console.log at line 4: after import uuid from 'react-native-uuid', add console.log('uuid:', uuid, 'v4:', uuid?.v4). If uuid is undefined or doesn't have v4, that's the crash.

Recommendation

Given that v2.6.4 has multiple issues and the library is semi-abandoned, I'd suggest one of:

Option A: Expand the patch to fix all identified issues (TDZ for _disableRowLoaders, potentially the uuid import). This means maintaining a larger patch long-term.

Option B: Pin to a safer version — if the Snyk vulnerability in v2.5.6 is in qs (the qs dependency was upgraded from ~6.9.1 to ^6.14.1), it may be possible to address the vulnerability by overriding just the qs dependency in package.json instead of upgrading the entire library.

Detailed Investigation

Root Cause Analysis

The v2.6.4 rewrite of GooglePlacesAutocomplete.js converted the component from using let variables and direct function assignments to useCallback/useMemo hooks throughout. This introduced multiple forward-reference issues where const bindings declared with useCallback are referenced in dependency arrays of hooks that appear earlier in the source.

The TDZ flow for _disableRowLoaders:

  1. Line 354: _requestNearby = useCallback(...) — deps include _disableRowLoaders (line 450)
  2. Line 581: getCurrentLocation = useCallback(...) — deps include _disableRowLoaders (line 629)
  3. Line 653: _disableRowLoaders = useCallback(...)declaration comes after usage

With Babel's block-scoping transform, constvar, so instead of a ReferenceError, the value is undefined. React sees [..., undefined, ...] in the deps, and on the next render when _disableRowLoaders has its real value, the deps change, triggering the callback to be recreated, potentially causing cascading re-renders.

The uuid dependency chain:

  • GooglePlacesAutocomplete.js line 4: import uuid from 'react-native-uuid'
  • react-native-uuid/dist/index.js: CJS module with exports.default = { v4: ... }
  • Line 172: useState(uuid.v4()) — called on every component mount
  • If Metro's interop doesn't correctly resolve the default export, uuid could be { default: { v4: fn } } instead of { v4: fn }, making uuid.v4 undefined

Evidence Chain

  • Library source at node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js — confirmed all TDZ locations by line number
  • Existing patch at patches/react-native-google-places-autocomplete/react-native-google-places-autocomplete+2.6.4+001+fix-tdz-crash.patch — only fixes line 161
  • react-native-uuid/dist/index.js — confirmed CJS export pattern with __esModule flag
  • @react-native/babel-preset includes @babel/plugin-transform-block-scoping — confirmed TDZ won't throw but will produce undefined

Relevant Code

  • node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js:161 — Patched TDZ (useRef)
  • node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js:450 — Unpatched TDZ (_disableRowLoaders in _requestNearby deps)
  • node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js:629 — Unpatched TDZ (_disableRowLoaders in getCurrentLocation deps)
  • node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js:172 — uuid.v4() call in useState
  • src/components/AddressSearch/index.tsx:364-477 — How Expensify consumes the component

Next Steps: Please share the crash stack trace so we can confirm which issue is the culprit. Reply with @MelvinBot implement this to create a comprehensive patch, or @MelvinBot <your feedback> to refine this analysis.

@situchan
Copy link
Contributor

@MelvinBot here's crash log:

installHook.js:1 ReferenceError: Cannot access '_disableRowLoaders' before initialization
at GooglePlacesAutocomplete (GooglePlacesAutocomplete.js:357:4)

@MelvinBot
Copy link
Contributor Author

🔍 Crash Analysis: _disableRowLoaders TDZ Error

Summary: The react-native-google-places-autocomplete v2.6.4 has multiple Temporal Dead Zone (TDZ) bugs introduced by an upstream refactoring that converted plain arrow functions into useCallback hooks without reordering declarations.

Root Cause: In v2.6.4, _requestNearby is declared as a useCallback at line 354 with _disableRowLoaders in its dependency array (line 450). But _disableRowLoaders is a const declared at line 653 — ~200 lines later. Because useCallback dependency arrays are evaluated synchronously during render, JavaScript hits the TDZ and crashes.

Why v2.5.6 didn't have this: In v2.5.6, these were plain arrow functions (const f = () => {...}) with no dependency arrays. References to later-declared functions only occurred inside callback bodies (executed lazily), never in eagerly-evaluated positions.

Note: The existing patch on this PR (react-native-google-places-autocomplete+2.6.4+001+fix-tdz-crash.patch) fixes a different TDZ bug (useRef(_request) at line 161). After that patch is applied, execution proceeds further and hits this second TDZ error at line 450. There may be additional TDZ violations deeper in the file (e.g., getCurrentLocation useCallback also references _disableRowLoaders and _requestNearby in its dependency array before they're declared).

Recommended Fix: Expand the existing patch to also fix the _disableRowLoaders TDZ (and any others). The most robust approach would be to convert the problematic useCallback hooks back to plain arrow functions (what v2.5.6 used), since this library is unmaintained and no upstream fix will come.

Detailed Investigation

TDZ Bug Chain

The v2.6.4 refactoring (commit 10b756af) wrapped plain arrow functions in useCallback hooks but didn't reorder declarations:

  1. TDZ Some initial fixes and code style updates #1 (fixed by existing patch): useRef(_request) at line 161 → _request declared at line 466
  2. TDZ Fix spaces #2 (this crash): _requestNearby useCallback dep array at line 450 → _disableRowLoaders declared at line 653
  3. Likely TDZ Add Expensify eslint #3: getCurrentLocation useCallback dep array (~line 629) → _disableRowLoaders at line 653

Evidence

// Line 354-465: _requestNearby declared with dependency array
const _requestNearby = useCallback(
    (latitude, longitude) => {
        // ...
        _disableRowLoaders(); // line 378 - used inside callback (lazy, would be fine)
        // ...
    },
    [
        _abortRequests,
        timeout,
        onTimeout,
        _disableRowLoaders, // line 450 - TDZ! Evaluated eagerly, but declared at line 653
        // ...
    ],
);

// Line 653-664: _disableRowLoaders finally declared (too late)
const _disableRowLoaders = useCallback(() => {
    // ...
}, [buildRowsFromResults]);

Relevant Code

  • node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js:354-465_requestNearby useCallback with TDZ reference
  • node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js:653-664_disableRowLoaders declaration

Next Steps: Reply with @MelvinBot fix this to expand the patch, or @MelvinBot <your feedback> to refine this analysis.

@situchan
Copy link
Contributor

@MelvinBot can we move _disableRowLoaders and _request functions to the top? This way, we can avoid those functions being called before definition.

@MelvinBot
Copy link
Contributor Author

Yes, moving _disableRowLoaders up is the right fix for this second TDZ crash. Specifically, _disableRowLoaders (currently line 653) should be moved to right after _filterResultsByTypes (~line 309), so the ordering becomes:

  1. buildRowsFromResults (line 248) — already there
  2. _filterResultsByTypes (line 290) — already there
  3. _disableRowLoaders — moved here from line 653
  4. _requestNearby (line 354) — already there, now its dependency is above it
  5. getCurrentLocation (line 581) — already there, now its dependency is above it

This is safe because _disableRowLoaders's only dependencies are resultsRef (line 143), setDataSource (line 165), and buildRowsFromResults (line 248) — all defined above the new position.

_request does not need to move. Its position at line 466 is fine — the only TDZ issue with _request was useRef(_request) on line 161, which the existing useRef(null) patch already fixes.

I'll update the patch to include this move.

The _disableRowLoaders useCallback was declared on line 653 but
referenced in the dependency arrays of _requestNearby (line 450) and
getCurrentLocation (line 629), causing a ReferenceError at render time.
Move the definition above _requestNearby so it is in scope when the
dependency arrays are evaluated.

Co-authored-by: Situ Chandra Shil <[email protected]>
@MelvinBot
Copy link
Contributor Author

Updated the patch to also fix the _disableRowLoaders TDZ crash.

Root cause: _disableRowLoaders was declared as a const useCallback on line 653 but referenced in the useCallback dependency arrays of _requestNearby (line 450) and getCurrentLocation (line 629). Since dependency arrays are evaluated eagerly during render, this caused ReferenceError: Cannot access '_disableRowLoaders' before initialization.

Fix: Moved _disableRowLoaders from line 653 to right before the "API REQUEST FUNCTIONS" section (after _getPredefinedPlace, before _requestNearby). All of _disableRowLoaders's dependencies (resultsRef, setDataSource, buildRowsFromResults) are defined above the new position, so this is safe.

The patch now fixes both TDZ crashes:

  1. useRef(_request)useRef(null) (line 161)
  2. _disableRowLoaders moved above its first reference (line 349 → before line 354)

@situchan
Copy link
Contributor

@MelvinBot there are a few more functions that need to be moved to the top:
Example: _renderDescription, getCurrentLocation
Can you find out all instances and fix all of them?

@MarioExpensify
Copy link
Contributor

@situchan do you want me to generate the adhoc or wait for the bot to finish these changes?

@situchan
Copy link
Contributor

@situchan do you want me to generate the adhoc or wait for the bot to finish these changes?

waiting for bot to finish the changes

@MarioExpensify
Copy link
Contributor

It seems the bot is stuck 😅

@MarioExpensify
Copy link
Contributor

@MelvinBot implement the changes requested by @situchan in their review comment here.

… patch

Move _renderDescription, hideListView, isNewFocusInAutocompleteResultList,
_onBlur, and _onFocus before _onPress so they are declared before use.
Move debounceData before _onChangeText for the same reason.

Co-authored-by: Mario Mazzotti <[email protected]>
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.

4 participants