Skip to content

[Due for payment 2026-05-28] Category - Parent category is disabled when selected #85359

Closed

Description

@jponikarchuk

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: 9.3.38-0
Reproducible in staging?: Yes
Reproducible in production?: No
If this was caught during regression testing, add the test name, ID and link from BrowserStack: #83200
Email or phone of affected tester (no customers): sdijnsoijsodosj@gmail.com
Issue reported by: Applause Internal Team
Bug source: Exploratory - Significant User Experience Deterioration
Device used: Mac 26.2 / Chrome
App Component: Money Requests

Action Performed:

Precondition:

  • Create both categories - Car and Car: Tesla
  1. Go to staging.new.expensify.com
  2. Go to workspace chat.
  3. Create an expense with Tesla subcategory.
  4. Open the expense.
  5. Click Category.
  6. On the search field, type Car.

Expected Result:

Car will be enabled because Car is a valid category (there are Car and Car: Tesla categories).

Actual Result:

Car is disabled when Car is a valid category. User will have to select a different category in order to select Car category.

Workaround:

Unknown

Platforms:

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

Screenshots/Videos

Video.mp4

View all open jobs on GitHub

Activity

  1. added
    DeployBlockerCashThis issue or pull request should block deployment
    BugSomething is broken. Auto assigns a BugZero manager.
    on Mar 16, 2026
  2. melvin-bot commented on Mar 16, 2026

    @melvin-bot

    You have been assigned to this deploy blocker because you recently merged this PR: #83200

  3. melvin-bot commented on Mar 16, 2026

    @melvin-bot

    💬 A slack conversation has been started in #expensify-open-source

  4. github-actions commented on Mar 16, 2026

    @github-actions
    Contributor

    👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:

    1. Identify the pull request that introduced this issue and revert it.
    2. Find someone who can quickly fix the issue.
    3. Fix the issue yourself.
  5. OSBotify commented on Mar 16, 2026

    @OSBotify
    Contributor

    🔍 Investigation Summary

    Classification: Frontend bug
    Causing PR: #83200 - "Multi-level categories with colons are shown with hierarchical indent..." by @ijmalik (High confidence)
    Related Issues: #82068

    Recommendation: REVERT

    PR #83200 introduced a regression in category selection logic that causes valid parent categories to be incorrectly disabled.

    Labels: Keeping DeployBlockerCash label as this is a Frontend bug requiring an App PR fix

    📋 Detailed Analysis

    Evidence

    PR #83200 was merged on 2026-03-13 to add hierarchical indentation for multi-level categories. The bug appeared in version 9.3.38-0, which includes this PR. The issue is reproducible on staging but not production, confirming the bug was introduced in this deployment.

    Verification

    The bug affects category selection in src/libs/CategoryOptionListUtils.ts, specifically the getCategoryOptionTree function modified by PR #83200.

    Key changes in the PR:

    1. Changed PARENT_CHILD_SEPARATOR from ": " (colon with space) to ":" (colon only)
    2. Removed the isOneLine parameter, forcing all category displays to use hierarchical mode
    3. Modified parent category disabled state logic

    Root Cause

    When categories like "Car" and "Car: Tesla" exist (note the space after colon in actual category names):

    1. The separator change from ": " to ":" causes "Car: Tesla" to be split into ["Car", " Tesla"] instead of ["Car", "Tesla"]
    2. During processing, a parent entry for "Car" is created from the "Car: Tesla" category
    3. Line 48 in CategoryOptionListUtils.ts calculates: isParentOptionDisabled = !selectedParentOption || !selectedParentOption.enabled || ...
    4. Since "Car" as a parent is not in selectedOptions, it gets disabled even though "Car" is a valid standalone enabled category
    5. This causes the reported bug where users cannot select the "Car" category after typing "Car" in the search field

    The issue occurs because the function treats any category that is a prefix of another category as a "parent" and applies different disabled logic to it, even when that category exists as a valid standalone option.

  6. MelvinBot commented on Mar 16, 2026

    @MelvinBot
    Contributor

    Proposal

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

    When a workspace has both a standalone category (e.g. "Car") and a subcategory that shares the parent name (e.g. "Car: Tesla"), searching for "Car" in the category picker while editing an expense that already uses the subcategory causes the standalone "Car" to appear disabled/grayed out. The user cannot select "Car" even though it is a valid, enabled category.

    What is the root cause of that problem?

    PR #83200 removed the isOneLine parameter from getCategoryOptionTree. Previously, search results used isOneLine = true, which rendered each category as a flat single-line entry without creating synthetic parent nodes. With that removed, search results now go through hierarchical tree building.

    The bug is a first-write-wins collision in the option Map. Here is the chain:

    1. When editing an expense with category "Car: Tesla", the category picker calls getCategoryListSections with selectedOptions = [{name: "Car: Tesla"}].
    2. At CategoryOptionListUtils.ts:120, the search array is built as [...selectedOptionsWithDisabledState, ...enabledCategories], which puts "Car: Tesla" before standalone "Car".
    3. At line 127, getCategoryOptionTree(searchCategories) is called without the selectedOptions parameter (it defaults to []).
    4. Processing "Car: Tesla" first: it splits by ':' into ["Car", " Tesla"]. At index 0, isChild = false, and selectedParentOption is undefined (because selectedOptions is empty). So isParentOptionDisabled = true. The Map entry for key "Car" is created with isDisabled: true (line 61).
    5. When standalone "Car" is processed next, optionCollection.has("Car") returns true (line 50), so it is skipped. The disabled parent placeholder wins.

    The core issue is at line 47-48: isParentOptionDisabled only checks the selectedOptions array to determine if a parent is a real category. Since selectedOptions is empty in the search path, all synthetic parent nodes are marked disabled — even when a real, enabled category with that name exists in the options array being processed.

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

    In getCategoryOptionTree at src/libs/CategoryOptionListUtils.ts:47-48, the isParentOptionDisabled calculation should also check the options array (the actual categories being rendered), not just selectedOptions. A parent node should be enabled when a real, enabled category with the same name exists in either options or selectedOptions.

    Replace the current parent disability check with one that looks up the parent name in both options and selectedOptions. If a matching enabled category is found in either source, the parent should not be disabled. This fixes the search path (where selectedOptions is empty but the real category exists in options) while preserving existing behavior for the "All" section (where selected categories are filtered out of options but exist in selectedOptions).

    What alternative solutions did you explore? (Optional)

    1. Fix the Map collision logic — instead of continue when a key already exists, overwrite if the new entry is a leaf (real category) and the existing entry is a disabled parent placeholder. This is more invasive and changes the general deduplication behavior.
    2. Restore isOneLine for search results only — this would effectively revert the search-specific change from PR Multi-level categories with colons are shown with hierarchical indent… #83200. This avoids the bug but loses the hierarchical display in search results that the PR intended to add.

    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.

  7. ZhenjaHorbach commented on Mar 16, 2026

    @ZhenjaHorbach
    Contributor

    @ijmalik
    Could you check this, please?

  8. melvin-bot commented on Mar 16, 2026

    @melvin-bot

    ⚠️ Looks like this issue was linked to a Deploy Blocker here

    If you are the assigned CME please investigate whether the linked PR caused a regression and leave a comment with the results.

    If a regression has occurred and you are the assigned CM follow the instructions here.

    If this regression could have been avoided please consider also proposing a recommendation to the PR checklist so that we can avoid it in the future.

  9. ijmalik commented on Mar 16, 2026

    @ijmalik
    Contributor
  10. ZhenjaHorbach commented on Mar 16, 2026

    @ZhenjaHorbach
    Contributor

    @ijmalik
    Any updates?

  11. 5 remaining items

  12. ZhenjaHorbach commented on Mar 16, 2026

    @ZhenjaHorbach
    Contributor

    @ZhenjaHorbach

    Just to clarify: should I wait until PR #85433 is reverted before creating my new PR? The PR is ready on my side.

    Thanks!

    It's already merged

  13. ijmalik commented on Mar 16, 2026

    @ijmalik
    Contributor

    @ZhenjaHorbach Kindly check the PR. #85448

  14. ijmalik commented on Mar 16, 2026

    @ijmalik
    Contributor

    @ZhenjaHorbach Kindly check the PR. #85448

  15. IuliiaHerets commented on Mar 16, 2026

    @IuliiaHerets

    Windows 10 / Chrome
    Not Repro
    v9.3.38-1

    bandicam.2026-03-16.15-06-16-767.mp4
  16. lanitochka17 commented on May 19, 2026

    @lanitochka17

    Deploy Blocker ##91133 was identified to be related to the PR ##85448 that attempted to fix this issue.

  17. melvin-bot commented on May 20, 2026

    @melvin-bot

    ⚠️ Looks like this issue was linked to a Deploy Blocker here

    If you are the assigned CME please investigate whether the linked PR caused a regression and leave a comment with the results.

    If a regression has occurred and you are the assigned CM follow the instructions here.

    If this regression could have been avoided please consider also proposing a recommendation to the PR checklist so that we can avoid it in the future.

  18. ijmalik commented on May 20, 2026

    @ijmalik
    Contributor

    This behavior is not a regression introduced by PR #85448. I’ve tested the same scenario in OldDot/Classic and confirmed that a colon‑only category : cannot be selected there either – it appears as an empty line in the dropdown and clicking it does nothing (the category field remains empty).

    Our PR’s behavior (the category not appearing in the list) is visually different but functionally identical to OldDot: the category : is not selectable.

    For a detailed breakdown, please see my comment in the PR: #85448 (comment)

    If the team decides that : should be selectable (unlike OldDot), that would be an enhancement request – but it is not a regression caused by this PR. I recommend closing this issue as “not a regression” (consistent with legacy behavior). Please let me know if you’d still like me to change the PR.

    Please see OldDot Demo Video

  19. changed the title [-]Category - Parent category is disabled when selected[/-] [+][Due for payment 2026-05-28] Category - Parent category is disabled when selected[/+] on May 21, 2026
  20. melvin-bot commented on May 21, 2026

    @melvin-bot

    The solution for this issue has been 🚀 deployed to production 🚀 in version 9.3.78-1 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

    If no regressions arise, payment will be issued on 2026-05-28. 🎊

  21. melvin-bot commented on May 21, 2026

    @melvin-bot

    @yuwenmemon The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the BugZero Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]

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.DailyKSv2Engineering

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions