Skip to content

[$175] Search-"type:expense vendor name", vendor name not highlighted and search result not correct #105375

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.25-0
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught during regression testing, add the test name, ID and link from BrowserStack: https://test-management.browserstack.com/projects/2219752/test-runs/81167661/folder/13176908/145045748/1923344198?sort=-identifier
Email or phone of affected tester (no customers): lekima20+635010@gmail.com
Issue reported by: Applause Internal Team
Bug source: Regression TC Execution
Device used: Win 11/Chrome
App Component: Search

Action Performed:

Precondition:

  • User is an admin of a workspace connected to QBO with Export company card expenses as set to Credit card
  • Go to the workspace chat create 2 non-reimbursable expenses: one with vendor "A B" and the other with vendor "Admin Denis"
  1. Open https://staging.new.expensify.com
  2. Navigate to Spend > Expenses
  3. Click the search icon at the top right and type "type:expense vendor:A B" > search
  4. Clear the search and type: "type:expense vendor A B" > search
  5. Clear the search and type: "type:expense vendor Admin Denis" > search

Expected Result:

Click the search icon at the top right and type type:expense vendor followed by the vendor name, verify the vendor name is highlighted like the other filter values. The search results match the filtered results

Actual Result:

Typing "type:expense vendor:A B" only the "A" is highlighted on the search box and displays no search result. Typing "type:expense vendor A B", the vendor name isn't highlighted, result displays both expenses with vendor "A B" and vendor "Admin Denis". Typing "type:expense vendor Admin Denis" displays no search result.

Workaround:

Unknown

Platforms:

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

Screenshots/Videos

Bug7299536_1793267750229.Recording__2645.mp4

View all open jobs on GitHub

Applause Internal Information
Exported by: Julia Ponikarchuk
Bug ID: 7299536

Upwork Automation - Do Not Edit
Issue OwnerCurrent Issue Owner: @jasperhuangg

Activity

  1. added
    BugSomething is broken. Auto assigns a BugZero manager.
    on Oct 29, 2026
  2. applause-bot commented on Oct 29, 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/d8eba1b8c483cf692fdae1f7eb9d1964794b7c8664a6436dad1b3942aa26e821

  3. MelvinBot commented on Oct 29, 2026

    @MelvinBot
    Contributor

    Proposal

    What is the root cause of that problem?

    This is mostly expected search syntax, plus one missing feature in the search box:

    1. vendor:A B (step 3). An unquoted value ends at the first space. This is true for every filter, not only vendor (baseRules.peggy:221). The query becomes vendor:A plus the keyword B, so only "A" is highlighted and nothing matches. Multi-word values must be quoted, for example vendor:"A B". Merchant, category, and tag work the same way.
    2. vendor A B and vendor Admin Denis (steps 4 and 5). Without a colon, these are plain keyword searches. The App sends the words to the server unchanged, and the server decides what matches. Nothing is highlighted because there is no filter.
    3. The App gap. Typing vendor: in the search box suggests no vendors. The suggestion switch handles tag and category, but has no VENDOR case (useAutocompleteSuggestions.ts:186-203). For other filters, picking a suggestion adds the quotes automatically (SearchRouter.tsx:476). For vendor, you have to type the quotes yourself, and the test step didn't include them.

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

    1. Add a VENDOR case to useAutocompleteSuggestions.ts. Fill it from the same synced vendor list that the Filters > Vendor picker uses. Selecting a vendor then inserts vendor:"A B" and highlights the full name.
    2. Update the regression test case to use vendor:"<name>" for names that contain spaces.

    Steps 4 and 5 (keyword results) are decided by the server. If those results are wrong, an internal engineer needs to look at them.

    What alternative solutions did you explore? (Optional)

    Let vendor: accept unquoted values that contain spaces. I rejected this because it would break the rule every other filter follows. It would also make vendor:A B ambiguous with a following keyword.

    Supporting evidence

    Possibly related: [$175] Filters - Vendor option is missing in filters


    Next Steps for Contributor+ team:
    To accept: @MelvinBot implement [this](https://github.com/Expensify/App/issues/105375) to create a draft PR.
    To refine: @MelvinBot <your feedback>
    To reject: Explain why you are rejecting Melvin's proposal.


    view run

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

    @melvin-bot

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

  6. changed the title [-]Search-"type:expense vendor name", vendor name not highlighted and search result not correct[/-] [+][$175] Search-"type:expense vendor name", vendor name not highlighted and search result not correct[/+] on Oct 29, 2026
  7. melvin-bot commented on Oct 29, 2026

    @melvin-bot
  8. camesenin commented on Oct 29, 2026

    @camesenin
  9. melvin-bot commented on Oct 29, 2026

    @melvin-bot

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

  10. khizzcr7 commented on Oct 29, 2026

    @khizzcr7

    Proposal

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

    Searching type:expense vendor:A B highlights only "A" and returns nothing, and colonless searches like type:expense vendor Admin Denis highlight nothing and return wrong results. The tester expects the vendor name to be highlighted like other filter values and the results to match the filtered expenses.

    What is the root cause of that problem?

    Two distinct behaviors, one of which is a genuine App gap:

    1. Unquoted multi-word values end at the first space. This is the search grammar working as designed, not a vendor-specific regression: vendor:A B parses as vendor A plus keyword B, so only "A" is highlighted and nothing matches both conditions. Multi-word vendor values must be quoted, e.g. vendor:"A B". Without a colon, vendor A B and vendor Admin Denis are plain keyword searches, so nothing is highlighted and the server decides what matches.
    2. The App gap: typing vendor: suggests no vendors. Verified against main source: the switch in src/hooks/useAutocompleteSuggestions.ts covers TAG, CATEGORY, CURRENCY, TAX_RATE and user filters, but has no vendor case. So a user can never discover the correct quoted form from the search box, which is exactly why the tester typed the unquoted forms.

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

    Add a vendor case to useAutocompleteSuggestions.ts, mirroring the existing TAG/CATEGORY cases:

    • Source the list from the workspace vendor list already synced for expenses, filtered by the typed substring (case-insensitive), capped at 10, and excluding vendor values already used in the current query (the same alreadyAutocompletedKeys dedup the TAG case uses).
    • Reuse the existing insertion path unchanged: sanitizeSearchValue in src/libs/SearchQueryUtils.ts already wraps any value containing a space in quotes, so selecting "A B" inserts vendor:"A B", which parses as a single vendor value and highlights in full.
    • Handle the lazy-load case explicitly: vendor lists load lazily, so while the list is not yet synced show no suggestions rather than stale data, following the category case's loader pattern. No parser change: the grammar already handles quoted values correctly, and rewriting it to absorb spaces would create ambiguity between vendor values and following keywords.

    What alternative solutions did you explore?

    • Parser change to absorb spaces into the vendor value: rejected, it would make vendor:A B ambiguous with a vendor filter plus a keyword, and would change behavior for every filter.
    • Auto-inserting a colon after vendor: rejected, it would reinterpret legitimate keyword searches.
    • Backend/server matching change: not needed; the server already matches quoted vendor values by text.

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

    • Jest test for the new vendor case: typing vendor: with a synced vendor list returns matching vendors; with no synced list returns an empty list.
    • Insertion test: selecting "A B" produces vendor:"A B" and reparsing yields exactly one vendor value A B, with neighbouring filters intact.
    • Dedup test: a vendor already used in the query is not suggested again.
    • Regression test for the grammar: unquoted vendor:A B still parses as vendor A plus keyword B (documented behaviour, unchanged).
  11. sonofkratos92 commented on Oct 29, 2026

    @sonofkratos92

    Proposal

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

    When searching in Spend > Expenses for expenses with multi-word vendor names like "A B" or "Admin Denis":

    1. Typing type:expense vendor:A B only highlights A in the search input, shows no vendor autocomplete suggestions to select "A B", and returns no results (because A is parsed as the vendor filter value and B is parsed as a separate free-text keyword).
    2. Typing type:expense vendor A B or type:expense vendor Admin Denis without a colon runs a plain keyword search rather than a vendor: filter.

    What is the root cause of that problem?

    1. In the search grammar (src/libs/SearchParser/baseRules.peggy:221), unquoted filter values terminate at whitespace, so multi-word filter values must be quoted (vendor:"A B"). When a user types vendor:A and then presses space followed by B (type:expense vendor:A B), defaultFilter in src/libs/SearchParser/autocompleteParser.peggy:39-75 parses vendor:A into ranges and freeTextFilter (autocompleteParser.peggy:83) parses B and resets autocomplete = null.
    2. src/hooks/useAutocompleteSuggestions.ts has no case CONST.SEARCH.SYNTAX_FILTER_KEYS.VENDOR: branch, so typing vendor: never suggests synced workspace vendors (unlike category:, tag:, or exported-to:), which is what normally wraps multi-word values in quotes via sanitizeSearchValue in src/components/Search/SearchRouter/SearchRouter.tsx:480.
    3. Even if a VENDOR case is added to useAutocompleteSuggestions.ts alone, CONST.SEARCH.SYNTAX_FILTER_KEYS.VENDOR is also missing from CONTINUATION_DETECTION_SEARCH_FILTER_KEYS in src/libs/SearchAutocompleteUtils.ts:683-691. Without VENDOR in CONTINUATION_DETECTION_SEARCH_FILTER_KEYS (and mapKey: CONST.SEARCH.SYNTAX_FILTER_KEYS.VENDOR on each suggestion item):
      • As soon as the user types a space in a multi-word vendor name (type:expense vendor:A B or type:expense vendor:Admin Denis), parseForAutocomplete returns autocomplete: null. Because useAutocompleteSuggestions.ts:157-168 only checks CONTINUATION_DETECTION_SEARCH_FILTER_KEYS when !autocomplete, the vendor suggestions disappear immediately after the space is typed.
      • When selecting a suggestion after typing a space, getTrimmedUserSearchQueryPreservingComma (src/libs/SearchAutocompleteUtils.ts:1045-1071) only trims back to vendor: (or the last comma) when fieldKey is in CONTINUATION_DETECTION_SEARCH_FILTER_KEYS; otherwise it falls back to getQueryWithoutAutocompletedPart(textInputValue), which returns the untrimmed string when parsedQuery.autocomplete is null and produces type:expense vendor:A B"A B".

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

    1. In src/libs/SearchAutocompleteUtils.ts, add CONST.SEARCH.SYNTAX_FILTER_KEYS.VENDOR to CONTINUATION_DETECTION_SEARCH_FILTER_KEYS:
    const CONTINUATION_DETECTION_SEARCH_FILTER_KEYS: SearchFilterKey[] = [
        CONST.SEARCH.SYNTAX_FILTER_KEYS.TO,
        CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM,
        CONST.SEARCH.SYNTAX_FILTER_KEYS.ASSIGNEE,
        CONST.SEARCH.SYNTAX_FILTER_KEYS.PAYER,
        CONST.SEARCH.SYNTAX_FILTER_KEYS.PAID_BY,
        CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTER,
        CONST.SEARCH.SYNTAX_FILTER_KEYS.ATTENDEE,
        CONST.SEARCH.SYNTAX_FILTER_KEYS.VENDOR,
    ];
    1. In src/hooks/useAutocompleteSuggestions.ts, import usePermissions from ./usePermissions and getMatchingVendors, getVendorFeaturePolicyIDs from @libs/PolicyUtils, check const isVendorMatchingBetaEnabled = isBetaEnabled(CONST.BETAS.VENDOR_MATCHING);, and add the VENDOR case to switch (autocompleteKey) using the same synced vendor source as VendorSelector.tsx with mapKey: CONST.SEARCH.SYNTAX_FILTER_KEYS.VENDOR:
            case CONST.SEARCH.SYNTAX_FILTER_KEYS.VENDOR: {
                const uniqueVendorNames = new Set<string>(
                    getVendorFeaturePolicyIDs(policies, isVendorMatchingBetaEnabled).flatMap((id) =>
                        getMatchingVendors(policies?.[`${ONYXKEYS.COLLECTION.POLICY}${id}`]).map((vendor) => vendor.name),
                    ),
                );
                const filteredVendors = Array.from(uniqueVendorNames)
                    .filter((vendorName) => {
                        if (!vendorName) {
                            return false;
                        }
                        const lowerVendorName = vendorName.toLowerCase();
                        return lowerVendorName.includes(autocompleteValue.toLowerCase()) && !alreadyAutocompletedKeys.has(lowerVendorName);
                    })
                    .sort((a, b) => localeCompare(a, b))
                    .slice(0, 10);
    
                return filteredVendors.map((vendorName) => ({
                    filterKey: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.VENDOR,
                    text: vendorName,
                    mapKey: CONST.SEARCH.SYNTAX_FILTER_KEYS.VENDOR,
                }));
            }

    With both changes in place, typing type:expense vendor:A B or type:expense vendor:Admin Denis keeps the matching vendor suggestion visible across spaces, and selecting it replaces the unquoted text after vendor: with vendor:"A B" (or vendor:"Admin Denis"), highlighting the full vendor name and returning the matching expense.

    What alternative solutions did you explore? (Optional)

    Changing the Peggy parser to allow unquoted spaces inside vendor: values would make vendor:A B ambiguous with trailing search keywords and break consistency with other filters (merchant:, category:, tag:). Adding VENDOR to useAutocompleteSuggestions together with CONTINUATION_DETECTION_SEARCH_FILTER_KEYS preserves the standard quoted syntax while supporting multi-word vendor autocomplete when typing spaces.

  12. apoorv-xs commented on Oct 29, 2026

    @apoorv-xs
  13. melvin-bot commented on Oct 29, 2026

    @melvin-bot

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

  14. ikevin127 commented on Oct 29, 2026

    @ikevin127
    Contributor

    Proposals review

    Only MelvinBot's proposal counts here, since this issue never had the Help Wanted label.

    Not a bug

    I tested this with a QBO workspace (company card expenses exported as Credit card) and non-reimbursable expenses with synced vendors A A and Five Stars. Everything matches MelvinBot's root cause:

    • type:expense vendor:A A: only the first A is highlighted and nothing is returned.
    • type:expense vendor:"A A": the full name is highlighted and the matching expense is returned.
    • type:expense vendor:Five Stars: only Five is highlighted and nothing is returned.
    • type:expense vendor:"Five Stars": the full name is highlighted and the matching expense is returned.

    A value without quotes ends at the first space (baseRules.peggy:221), so vendor:Five Stars searches vendor:Five plus the keyword Stars. The same is true for every free-text filter (merchant:, description:). Multi-word values need quotes.

    The issue's colonless searches (vendor A B, vendor Admin Denis) aren't vendor filters at all. They're keyword searches, so nothing is highlighted and the server decides what matches. The test steps come from Tests step 6 of #104351 (type:expense vendor:<name>), which didn't say that multi-word names need quotes.

    Recommendation

    Close this as not a bug, and update the regression test case to quote multi-word vendor names, e.g. type:expense vendor:"A B".

    MelvinBot's vendor: autocomplete idea would help users find the right syntax, but it's a new feature rather than a fix (merchant: has no autocomplete either). Up to you whether to track it separately.

    🎀👀🎀 C+ reviewed

  15. melvin-bot commented on Oct 29, 2026

    @melvin-bot

    Triggered auto assignment to @jasperhuangg, see https://stackoverflow.com/c/expensify/questions/7972 for more details.

  16. jasperhuangg commented on Nov 2, 2026

    @jasperhuangg
    Contributor

    Created a QA request to update the vendor-search regression test to quote multi-word names. The request links the reported run and the existing vendor-search case, and asks Applause to confirm the affected case and validate the updated steps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

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