Skip to content

[$175] Workspace Settings- Can't connect to Zoho Books #105694

Closed

Description

@applause-bot

If you haven’t already, check out our contributing guidelines for onboarding. To join our Slack channel, fill out this form.


Version Number: v9.5.28-4
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught during regression testing, add the test name, ID and link from BrowserStack: #105240
Email or phone of affected tester (no customers): N/A
Issue reported by: Applause Internal Team
Bug source: Pull Request QA execution
Device used: Windows 11 / Chrome, iPhone 13 / iOS 27 Beta, Samsung Galaxy A52 / Android 14
App Component: Workspace Settings

Action Performed:

Preconditions: logged in to a new Expensifail account, and create a control workspace on that account

Steps:

  1. Navigate to Workspace setting -> Connections
  2. Search for Zoho Books and click on it
  3. Proceed with Zoho Books connections until navigated back to ND

Expected Result:

User can sucessfully connect to Zoho Books after navigated back to ND

Actual Result:

Nothing happened after user navigated back to ND

Workaround:

Unknown

Platforms:

  • Android: App
  • Android: mWeb Chrome
  • iOS: App
  • iOS: mWeb Safari
  • iOS: mWeb Chrome
  • Windows: Chrome
  • MacOS: Chrome Safari

Screenshots/Videos

Bug7303105_1793657560419.bandicam_2026-11-03_04-58-16-600.mp4

View all open jobs on GitHub

Applause Internal Information
Exported by: Mita Rachim
Bug ID: 7303105

Upwork Automation - Do Not Edit

Activity

  1. applause-bot commented on Nov 2, 2026

    @applause-bot
    Author

    While Applause doesn't embed attachments for this bug, here are the links for quick view:
    https://platform.applause.com/services/links/v1/external/e2ccaae0ce60c62b3eaa8938c8f6558e3f95d500a3bc1ab0335a679cea173896

  2. added
    BugSomething is broken. Auto assigns a BugZero manager.
    on Nov 2, 2026
  3. MelvinBot commented on Nov 2, 2026

    @MelvinBot
    Contributor

    Issue Analysis

    Root Cause: This appears to be a backend/internal issue. A separate internal investigation is needed.

    The App side looks correct. It opens the Zoho Books OAuth link the same way it opens Xero's, then waits for the backend to push the new connection to the workspace. If the backend saves neither a connection nor an error, the Connections page has nothing new to show, so "nothing happens."

    Recommended Fix: No App change is recommended. An internal engineer should check why the Zoho Books OAuth callback doesn't create the connection in this flow. This likely overlaps with [Release 1.1] Zoho Books connection error is not displayed when the connect flow fails, which is waiting on a backend callback change so failures get saved and shown.

    Investigation details

    App flow (no defect found)

    Why the screen doesn't change

    Alternative considered (not verified)
    New workspaces have Connections turned off. The App turns it on with a queued write, then opens the setup flow one frame later (AccountingContext/index.tsx:150-171). If the callback refuses to connect while Connections is still off, the connection could fail. This matches the "new account + new workspace" precondition, but I couldn't confirm it.

    Not caused by the QA'd PR
    The bug also reproduces in production, so Add Zoho Books export settings UI, manual export, and Mark as exported didn't introduce it. That PR changes export settings, not the connect flow.

    Confidence: medium. The App code evidence is strong, but I couldn't check production logs in this run. Backend logs for the tester's ConnectPolicyToZohoBooks callback would confirm the failure.


    Next Steps: Escalate to an internal engineer to check the Zoho Books OAuth callback, or reply with @MelvinBot <your feedback> to refine this analysis.


    view run

  4. added
    ExternalAdded to denote the issue can be worked on by a contributor
    on Nov 2, 2026
  5. melvin-bot commented on Nov 2, 2026

    @melvin-bot

    Triggered auto assignment to Contributor-plus team member for initial proposal review - @huult (External)

  6. changed the title [-]Workspace Settings- Can't connect to Zoho Books[/-] [+][$175] Workspace Settings- Can't connect to Zoho Books[/+] on Nov 2, 2026
  7. melvin-bot commented on Nov 2, 2026

    @melvin-bot
  8. camesenin commented on Nov 2, 2026

    @camesenin

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    After completing the Zoho Books connection flow and returning to New Expensify, the workspace does not visibly show a successful connection. The report does not establish whether authorization failed, the connection was not persisted, or the interface failed to display the updated state.

    What is the root cause of that problem?

    Unverified. This case does not yet support a defensible implementation proposal.

    No source snippets, callback trace, API responses, Onyx mutations, or failing automated tests were supplied. I could not retrieve PR #105240 or the relevant source through the available access methods, and no local Expensify checkout was found. Consequently, exact file paths, line numbers, and a causal TypeScript diff cannot be established without fabrication.

    The reference to PR #105240 identifies the QA context; it does not establish that this PR introduced the defect.

    The following explanations remain hypotheses:

    • Zoho authorization or the server-side token exchange fails.
    • The callback loses or incorrectly identifies the workspace.
    • The server establishes the connection but does not deliver the corresponding client update.
    • The client receives the update but renders stale connection state.

    There is no evidence supporting a security vulnerability, credential disclosure, or CVSS assessment.

    What changes do you think we should make in order to solve the problem?

    Do not select a production change until the failing transition is demonstrated. A minimal diff must fix the verified cause; minimizing line count alone does not establish correctness.

    Capture one reproduction against v9.5.28-4, with credentials and authorization codes redacted:

    1. Record the connection initiation, callback destination, and workspace identifier.
    2. Capture the connection-completion request and response, if present.
    3. Compare persisted connection state with the client’s incoming Onyx updates.
    4. Identify the first transition that differs from a successful connection.

    Then patch the responsible layer and provide a commit-pinned source reference and failing-before/passing-after evidence.

    A forced refresh, optimistic “connected” flag, or navigation change is currently unsupported: each could conceal an unsuccessful connection while making the interface appear fixed.

    Expensify’s contributing guidelines require reproduction before proceeding with a proposal.

    What alternative solutions did you explore? (Optional)

    No MelvinBot proposal was supplied, so there is no concrete implementation to critique.

    Reject these unsupported approaches:

    • Set success on return: returning from authorization does not prove that the connection was persisted.
    • Add a timeout or unconditional reload: neither identifies nor reliably repairs the failing transition.
    • Refactor shared OAuth handling: broadens regression exposure before establishing whether the defect is shared.

    Existing proposals and duplicate issues were not verified; originality cannot be claimed.

    What automated tests can you add to prevent this from re-occurring?

    Once the responsible function or component is identified, add a regression test to its existing Jest suite:

    • Successful completion: seed a disconnected workspace, deliver the verified successful completion payload through the actual handler, and assert that the correct workspace displays the persisted connection without a manual reload.
    • Canceled or failed authorization: assert that returning to the app does not mark the workspace connected.
    • Workspace isolation: complete authorization for workspace A while workspace B exists; assert that B remains unchanged.

    The primary test must fail on the affected revision and pass with the patch. Mocking the final connected state directly would bypass the suspected defect.

    No tests were executed. Exact Jest code and a TypeScript diff remain blocked by unavailable source and reproduction evidence.

    Contributor details
    Your Expensify account email: camesenin@gmail.com
    Upwork Profile Link: https://www.upwork.com/freelancers/~01b60d704ba377be83

  9. melvin-bot commented on Nov 2, 2026

    @melvin-bot

    ✅ Contributor details stored successfully. Thank you for contributing to Expensify!

  10. huult commented on Nov 3, 2026

    @huult
    Contributor
    Screen.Recording.2026-11-03.at.10.01.48.mov

    @lakchote It looks like there haven't been any callbacks, so I suspect the account hasn't been added to the account test yet. I think we should share the test email with QA so they can verify this flow.

    Also, I think we should display error messages when something goes wrong so users know what happened.

  11. voxturrlabs commented on Nov 3, 2026

    @voxturrlabs

    Proposal

    Please re-state the problem that we are trying to solve in this issue.

    After finishing the Zoho Books OAuth flow and coming back to New Expensify, the workspace shows nothing: Zoho Books isn't connected, no sync starts, and no error appears.

    What is the root cause of that problem?

    There are two parts. The connection itself is created on the backend. The App side only adds to the problem by never showing what happened.

    1. The connection is never created (backend or Zoho app configuration). getZohoBooksSetupLink (src/libs/actions/connections/ZohoBooks.ts:36-41) only sends policyID, the same as Xero. The Zoho Books connection only appears once the backend pushes policy.connections.zohoBooks. In @huult's video no callback reaches the backend at all, which points to the Zoho OAuth client not accepting this test account. An internal engineer needs to check that.

    2. The App never re-reads the connection state when the user comes back. WorkspaceConnectionsPage.tsx:124-128 fetches only on mount and on reconnect:

      useNetwork({onReconnect: () => fetchConnectionsData(policyID, canUseMergeConnections, isRecruitingBetaEnabled)});
      
      useEffect(() => {
          fetchConnectionsData(policyID, canUseMergeConnections, isRecruitingBetaEnabled);
      }, [policyID, canUseMergeConnections, isRecruitingBetaEnabled]);
    3. Web lands on the wrong page under the Connections beta. The web deep-link screen ZohoBooksOAuthPage/index.tsx:20-23 always goes back to the old Accounting page:

      callback: () => Navigation.goBack(ROUTES.POLICY_ACCOUNTING.getRoute(policyID)),

      The native screen (ZohoBooksOAuthPage/index.native.tsx:24) already uses getAccountingConnectionsRoute(isUnifiedConnectionsBetaEnabled, policyID). So a web user who started from Workspace > Connections comes back to a different page from the one they left.

    What changes do you think we should make in order to solve the problem?

    Part 1 needs an internal fix: allow-list the test account or domain on the Zoho OAuth client, or fix the callback. The App changes below make sure the user always sees the result, whether it's a success or an error.

    1. Re-fetch when the user comes back to the app. In WorkspaceConnectionsPage.tsx, also fetch when the app becomes visible again, using the existing Visibility helper (src/libs/Visibility). It works for both a web tab switch and a native app foreground:

      useEffect(() => {
          const unsubscribe = Visibility.onVisibilityChange(() => {
              if (!Visibility.isVisible()) {
                  return;
              }
              fetchConnectionsData(policyID, canUseMergeConnections, isRecruitingBetaEnabled);
          });
          return unsubscribe;
      }, [policyID, canUseMergeConnections, isRecruitingBetaEnabled]);

      OpenPolicyAccountingPage is a read, so an extra call when the tab regains focus is cheap. It brings back connections.zohoBooks (or its error) even if the Pusher update was missed.

    2. Re-fetch when the native OAuth screen closes. AccountingSetupWebViewPage is a screen inside the app, so the visibility event doesn't fire when it closes. Re-fetch when the Connections page gets focus again:

      useFocusEffect(() => {
          fetchConnectionsData(policyID, canUseMergeConnections, isRecruitingBetaEnabled);
      });

      This could replace the mount effect, because focus also fires on mount.

    3. Return to the page the user started from on web. In ZohoBooksOAuthPage/index.tsx, use the same route helper as the native screen:

      const isUnifiedConnectionsBetaEnabled = useIsUnifiedConnectionsBetaEnabled();
      ...
      callback: () => Navigation.goBack(getAccountingConnectionsRoute(isUnifiedConnectionsBetaEnabled, policyID)),

    With the backend fix, the user returns to Connections and sees Zoho Books syncing. Without it, the page now shows the latest backend state, including the connection error from #104933, instead of looking frozen.

    What alternative solutions did you explore? (Optional)

    • Optimistically mark Zoho Books as "connecting" when OAuth starts. This would hide a real failure behind a fake status, and the App can't tell when the user gives up in the other tab.
    • Poll OpenPolicyAccountingPage while the OAuth tab is open. This adds repeated requests for a case that a single fetch on return already covers.

    Automated Tests

    In tests/ui/WorkspaceConnectionsPageTest.tsx:

    • Given the Connections page is mounted. When the app goes to the background and becomes visible again. Then OpenPolicyAccountingPage is called again for the policy.
    • Given the backend responds with connections.zohoBooks. When that refetch resolves. Then Zoho Books appears in the connected list.

    In tests/ui/ZohoBooksOAuthPageTest.tsx (web):

    • Given the unified Connections beta is on. When the OAuth deep-link screen opens. Then Navigation.goBack is called with WORKSPACE_CONNECTIONS. With the beta off, it's called with POLICY_ACCOUNTING.

    Contributor details
    Expensify account email: systemadmin@voxturrlabs.com
    Upwork Profile Link: https://www.upwork.com/freelancers/~010efadac9ff3c3d2a/

  12. lakchote commented on Nov 3, 2026

    @lakchote
    Contributor

    @huult QA already has access, and the callbacks did reach us. QA's tries last night failed with "Zoho Books organizations with multiple locations are not supported yet." That was because our test org briefly had a second location from our own testing. It's back to one location now, so I asked QA to retest with the same account. If it passes, I'll close this as a dupe of #104933, which is the App not showing that error.

    The 3 tries right before your comment failed with "A Zoho Books Professional plan or higher is required to connect." If those were yours, your Zoho org needs to be on Professional or higher.

  13. IuliiaHerets commented on Nov 3, 2026

    @IuliiaHerets

    Issue is not repro anymore, checked on Web, Android and iOS, v9.5.28-5

    ScreenRecording_11-03-2026.16-18-35_1.mp4
    Screen_Recording_20261103_162856_Expensify.mp4
    bandicam.2026-11-03.16-24-03-297.mp4
  14. self-assigned this
    on Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

BugSomething is broken. Auto assigns a BugZero manager.DailyKSv2ExternalAdded to denote the issue can be worked on by a contributor

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions