Skip to content

[Due for payment 2026-10-13] [$175] Report Fields are not displayed on reports in New Expensify despite being enabled and configured #102788

Open

Description

@izarutskaya

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


Version Number:
Reproducible in staging?: Needs Reproduction (unable to reproduce according steps)
Reproducible in production?: Needs Reproduction (unable to reproduce according steps)
If this was caught during regression testing, add the test name, ID and link from BrowserStack:
Email or phone of affected tester (no customers):
Logs: https://stackoverflow.com/c/expensify/questions/4856
Expensify/Expensify Issue URL:
Issue reported by: @jalynmsc
Slack conversation (hyperlinked to channel name): #expensify_bugs

Action Performed:

  1. Goes to the workspace in New Expensify.
  2. Goes to Reports and confirms Report fields are enabled.
  3. Confirms Department, Project Code, and Purpose are configured as List Report Fields with values.
  4. Creates an expense report under the workspace.
  5. Opens the report and checks the report details.
  6. The configured Report Fields do not appear for selection.

Expected Result:

Department, Project Code, and Purpose should appear on the expense report so the user can select the appropriate values.

Actual Result:

None of the configured Report Fields appear on the expense report, despite Report Fields being enabled and the fields containing values.

Workaround:

Unknown

Platforms:

Select the officially supported platforms where the issue was reproduced:

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

Screenshots/Videos

For the customer's details check the OP

View all open jobs on GitHub

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

Activity

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

    @MelvinBot
    Contributor

    Proposal

    Confidence: medium. The code path below hides list fields exactly as described. I couldn't check the customer's workspace data to confirm it matches.

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

    List report fields (Department, Project Code, Purpose) don't appear on expense reports, even though Report fields are enabled and each field has values.

    What is the root cause of that problem?

    The report view hides a list field unless its disabledOptions array has at least one false entry. It never checks values. If disabledOptions is empty or shorter than values, the field is hidden. The workspace settings page reads the same data differently: it treats a missing disabledOptions entry as enabled, so the admin sees enabled values that never show on reports.

    Fields created in New Expensify always add one false per value, so QA can't reproduce this. I created a Department list field on web and it showed correctly:

    Department list field shows on a new expense report (repro attempt)

    Fields created another way (for example, Classic, the API, or an accounting import) can have a mismatched array. All three of the customer's fields are list fields, so all three are hidden.

    Code references

    Other cause I couldn't rule out: If the admin turned Report fields off and on, the backend may have disabled every value ([Due for Payment 12/23][$250] Report field - Disabled list-type report fields remain visible in the expense report, steps 6-7). In that case the values show as Disabled in settings and the fields are hidden on purpose. The customer fixes that by re-enabling the values.

    Ruled out: plan type (Collect, Control, and Submit all pass), field target (settings use the same filter), and empty reports (fields render with no expenses).

    To confirm: compare values with disabledOptions for the three fields in the customer's policy fieldList.

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

    1. In ReportUtils.ts, add a helper that decides whether a list field has an enabled value. It loops over values and treats a missing disabledOptions entry as enabled, matching FieldsListValuesPage.
    2. Use the helper in shouldHideSingleReportField and in the isListFieldEmpty checks in FieldsSettingsPage and FieldsInitialValuePage.
    3. Add unit tests for values: ['A','B'] with disabledOptions: [], and for 3 values with disabledOptions: [true]. The field should be visible in both cases.

    What alternative solutions did you explore? (Optional)

    Fix the backend so disabledOptions always matches values in length. That would need an internal engineer. The App change is still worth making so the report view and settings agree.


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


    view run · view recording

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

    @melvin-bot

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

  5. changed the title [-]Report Fields are not displayed on reports in New Expensify despite being enabled and configured[/-] [+][$175] Report Fields are not displayed on reports in New Expensify despite being enabled and configured[/+] on Oct 1, 2026
  6. melvin-bot commented on Oct 1, 2026

    @melvin-bot
  7. camesenin commented on Oct 1, 2026

    @camesenin

    Proposal

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

    List-type report fields (such as Department, Project Code, Purpose) are not displayed on reports in New Expensify even though Report Fields are enabled and the list fields contain configured values.

    What is the root cause of that problem?

    In src/libs/ReportUtils.ts, line 14216:

    function shouldHideSingleReportField(reportField: PolicyReportField) {
        const hasEnableOption = reportField.type !== CONST.REPORT_FIELD_TYPES.LIST || reportField.disabledOptions.some((option) => !option);
    
        return isReportFieldOfTypeTitle(reportField) || !hasEnableOption;
    }
    1. shouldHideSingleReportField determines whether a list field has any enabled options by running reportField.disabledOptions.some((option) => !option).
    2. However, for workspaces imported from OldDot / Classic, created via the API, or integrated with external accounting systems, reportField.disabledOptions may be an empty array [], undefined, or shorter than reportField.values (where options are enabled by default unless explicitly disabled).
    3. When disabledOptions is empty ([]), [].some(...) returns false, causing hasEnableOption to evaluate to false, which hides the report field entirely even though reportField.values has valid options.
    4. In contrast, DynamicEditReportFieldPage.tsx line 222 determines active options correctly by checking:
    fieldOptions={policyField.values.filter((_value: string, index: number) => !policyField.disabledOptions.at(index))}

    When disabledOptions is empty, disabledOptions.at(index) returns undefined, which correctly treats the value as enabled (!undefined === true).

    Because shouldHideSingleReportField incorrectly evaluates the empty disabledOptions array instead of mapping against values, the entire list field is hidden from the report.

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

    In src/libs/ReportUtils.ts:
    Update shouldHideSingleReportField to check if at least one value in reportField.values is enabled, matching the logic in DynamicEditReportFieldPage.tsx:

    function shouldHideSingleReportField(reportField: PolicyReportField) {
        const hasEnableOption =
            reportField.type !== CONST.REPORT_FIELD_TYPES.LIST ||
            (reportField.values ?? []).some((_, index) => !reportField.disabledOptions?.[index]);
    
        return isReportFieldOfTypeTitle(reportField) || !hasEnableOption;
    }

    This ensures that:

    1. If disabledOptions is empty or omitted, existing values are correctly treated as enabled and the field is rendered.
    2. If all options in disabledOptions are explicitly true, hasEnableOption is false and the field is hidden as intended.
    3. If values is empty ([]), hasEnableOption evaluates to false and the empty list field is hidden.

    Also add unit tests in tests/unit/ReportUtilsTest.ts:

    • Assert that shouldHideSingleReportField returns false (shows field) when values: ['Sales', 'Engineering'] and disabledOptions: [].
    • Assert that shouldHideSingleReportField returns true (hides field) when values: ['Sales'] and disabledOptions: [true].

    What alternative solutions did you explore? (Optional)

    • Populating disabledOptions on the backend for legacy policies. This would require backend changes across OldDot/migration scripts, whereas fixing the client-side check aligns ReportUtils.ts with DynamicEditReportFieldPage.tsx and handles legacy/external policy data reliably.
  8. bonnhatnguyen commented on Oct 1, 2026

    @bonnhatnguyen

    Proposal for Issue #102788: [$175] Report Fields are not displayed on reports in New Expensify despite being enabled and configured

    Contributor Details

    • Contributor: @bonnhatnguyen
    • Email: bonnhatnguyen0@gmail.com
    • Upwork: https://www.upwork.com/freelancers/~0139ed4098bdc50182

    Proposal

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

    List-type report fields (such as Department, Project Code, Purpose) are not rendered on expense reports in New Expensify even though Report Fields are enabled in workspace settings and the list field has configured options.


    What is the root cause of that problem?

    1. In src/libs/ReportUtils.ts:14238, shouldHideSingleReportField determines whether a list field has any active options:
      function shouldHideSingleReportField(reportField: PolicyReportField) {
          const hasEnableOption = reportField.type !== CONST.REPORT_FIELD_TYPES.LIST || reportField.disabledOptions.some((option) => !option);
      
          return isReportFieldOfTypeTitle(reportField) || !hasEnableOption;
      }
    2. In policies imported from OldDot/Classic, populated via external accounting integrations (e.g. NetSuite, QuickBooks Online, Xero), or created without explicitly toggling option states, reportField.disabledOptions is an empty array [] (or shorter than reportField.values), because options are enabled by default unless explicitly disabled.
    3. In JavaScript, [].some(...) returns false. Consequently, hasEnableOption evaluates to false, causing shouldHideSingleReportField to return true. This causes MoneyRequestViewReportFields.tsx and MoneyReportView.tsx to completely hide the field from the report.
    4. Furthermore, this flawed assumption is duplicated in two other places:
      • In src/pages/workspace/fields/FieldsSettingsPage.tsx:78:
        const isListFieldEmpty = isListFieldType && reportField.disabledOptions.filter((disabledListValue) => !disabledListValue).length <= 0;
        When disabledOptions is [], isListFieldEmpty evaluates to true, erroneously hiding the Initial value row in the field settings!
      • In src/pages/workspace/fields/FieldsInitialValuePage.tsx:55:
        const availableListValuesLength = (reportField?.disabledOptions ?? []).filter((disabledListValue) => !disabledListValue).length;
        availableListValuesLength calculates 0 when disabledOptions is [].
    5. In contrast, src/pages/DynamicEditReportFieldPage.tsx:222 already handles this correctly by iterating over values and treating missing entries in disabledOptions as enabled:
      fieldOptions={policyField.values.filter((_value: string, index: number) => !policyField.disabledOptions.at(index))}

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

    1. In src/libs/ReportUtils.ts:

    Export a reusable helper hasEnabledOptions:

    /**
     * Checks whether a report field has any enabled options.
     * For non-list fields, always returns true.
     * For list fields, checks if at least one value in `values` is enabled (i.e. not marked as true in `disabledOptions`).
     */
    function hasEnabledOptions(reportField: PolicyReportField | undefined): boolean {
        if (!reportField) {
            return false;
        }
        if (reportField.type !== CONST.REPORT_FIELD_TYPES.LIST) {
            return true;
        }
        return (reportField.values ?? []).some((_, index) => !reportField.disabledOptions?.at(index));
    }

    Update shouldHideSingleReportField:

    function shouldHideSingleReportField(reportField: PolicyReportField) {
        const hasEnableOption = hasEnabledOptions(reportField);
    
        return isReportFieldOfTypeTitle(reportField) || !hasEnableOption;
    }

    Export hasEnabledOptions from ReportUtils.ts.

    2. In src/pages/workspace/fields/FieldsSettingsPage.tsx:

    Replace the duplicate check with hasEnabledOptions:

    const isListFieldEmpty = isListFieldType && !ReportUtils.hasEnabledOptions(reportField);

    3. In src/pages/workspace/fields/FieldsInitialValuePage.tsx:

    Update availableListValuesLength to accurately count available options:

    const availableListValuesLength = (reportField?.values ?? []).filter((_, index) => !reportField.disabledOptions?.at(index)).length;

    4. Add Unit Tests in tests/unit/ReportUtilsTest.ts:

    Add test cases verifying:

    • List field with configured values and empty disabledOptions: [] returns true for hasEnabledOptions and false for shouldHideSingleReportField.
    • List field with values: ['A', 'B'] and disabledOptions: [true] returns true (Option 'B' is enabled).
    • List field with values: ['A', 'B'] and disabledOptions: [true, true] returns false (all disabled).
    • List field with empty values: [] returns false.

    What alternative solutions did you explore? (Optional)

    • Backend normalization: Modifying backend sync scripts to pre-fill disabledOptions: [false, false, ...] for all existing legacy policies. This would take significant backend migration effort, whereas fixing the client-side check correctly matches DynamicEditReportFieldPage.tsx, is resilient to legacy/external data, and guarantees consistent UI across report views and settings.
  9. Eskalifer1 commented on Oct 1, 2026

    @Eskalifer1
    Contributor

    @MelvinBot Based on the logs customer had "disabledOptions":[] What could be possible reason? Could this be BE issue? Or this should be foxed on FE?

  10. camesenin commented on Oct 1, 2026

    @camesenin

    Hi @Eskalifer1! As detailed in my proposal above, this should definitely be fixed on the Frontend for three key reasons:

    1. Inconsistency in the Frontend codebase: In DynamicEditReportFieldPage.tsx (line 222), the frontend already treats missing or empty disabledOptions entries as enabled:
    fieldOptions={policyField.values.filter((_value: string, index: number) => !policyField.disabledOptions.at(index))}

    When disabledOptions: [], disabledOptions.at(index) returns undefined, which evaluates to enabled (!undefined === true). Only ReportUtils.ts (shouldHideSingleReportField) broke this convention by running disabledOptions.some((opt) => !opt), which returns false on empty arrays.

    1. Why the BE has disabledOptions: []: Workspaces imported from OldDot/Classic, created via the API, or populated through external accounting integrations (NetSuite, QuickBooks) only populate disabled flags when an admin explicitly toggles an option off. Options are enabled by default, so disabledOptions: [] is a valid and expected state representing "no options are disabled".

    2. Architectural Safety & Speed: A backend migration would require updating and backfilling [false, false, ...] across historical policies and third-party accounting sync pipelines. Fixing it on the frontend aligns ReportUtils.ts with DynamicEditReportFieldPage.tsx and provides instant, resilient support across all platforms without touching the backend.

  11. Eskalifer1 commented on Oct 1, 2026

    @Eskalifer1
    Contributor

    I wasn't able to reproduce this myself, but the logs show what's going on.

    Root cause

    The backend sends the customer's Department field like this (other properties omitted):

    "expensify_field_id_DEPARTMENT": {
        "type": "dropdown",
        "disabledOptions": [],
        "values": ["1001-...", "1002-...", ... 236 values]
    }

    disabledOptions is an index-aligned array of flags for values (true = disabled). When a field is created in NewDot, every value gets an explicit false, so the array always matches values in length. This field wasn't created in NewDot, and its disabledOptions is empty.

    The current check in shouldHideSingleReportField only looks at what's inside disabledOptions:

    App/src/libs/ReportUtils.ts

    Lines 14234 to 14238 in 102de14

    function shouldHideSingleReportField(reportField: PolicyReportField) {
    const hasEnableOption = reportField.type !== CONST.REPORT_FIELD_TYPES.LIST || reportField.disabledOptions.some((option) => !option);
    return isReportFieldOfTypeTitle(reportField) || !hasEnableOption;
    }

    const hasEnableOption = reportField.type !== CONST.REPORT_FIELD_TYPES.LIST || reportField.disabledOptions.some((option) => !option);

    [].some(...) is always false, so the field gets hidden. Because the same function is used for the field violation RBR, the fieldRequired violation the backend returned on submit isn't shown either. The user ends up with a required field they can't see.

    Other places in the app already treat a missing index as enabled. FieldsListValuesPage uses enabled: !disabledListValues.at(index) and DynamicEditReportFieldPage filters with !disabledOptions.at(index). That's why the admin sees all values as enabled in settings. isListFieldEmpty in FieldsSettingsPage.tsx:78 has the same narrow check as shouldHideSingleReportField.

    Backend

    It's worth checking for this specific customer whether all the values are actually set to “enabled.” After all, part of the problem could also lie on the backend if there are “disabled” values and the backend is sending an empty array. This most likely happens on Classic, since on ND this array is never empty.

    Proposed frontend fix

    Check against values and treat a missing disabledOptions entry as enabled. A field whose values are all disabled ([true, true, ...]) is still hidden, so the behavior from the original "hide disabled list fields" fix stays the same.

    function hasEnabledListValue(reportField: PolicyReportField): boolean {
        return reportField.values.some((_, index) => !reportField.disabledOptions.at(index));
    }
    
    function shouldHideSingleReportField(reportField: PolicyReportField) {
        const hasEnableOption = reportField.type !== CONST.REPORT_FIELD_TYPES.LIST || hasEnabledListValue(reportField);
    
        return isReportFieldOfTypeTitle(reportField) || !hasEnableOption;
    }

    And in FieldsSettingsPage.tsx:

    const isListFieldEmpty = isListFieldType && !hasEnabledListValue(reportField);

    Unit tests to add:

    • values: ['A', 'B'], disabledOptions: [] → visible
    • values: ['A', 'B', 'C'], disabledOptions: [true] → visible
    • values: ['A', 'B'], disabledOptions: [true, true] → hidden

    We can move forward with Melvin based on this comment

    🎀 👀 🎀 C+ reviewed

  12. 28 remaining items

  13. melvin-bot commented on Oct 6, 2026

    @melvin-bot

    @Eskalifer1

    The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.3-4 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-10-13. 🎊

    The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ 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]. If no checklist is needed for this issue, you can click: [no checklist button]

  14. Eskalifer1 commented on Oct 12, 2026

    @Eskalifer1
    Contributor

    Contributor+ Checklist:

    • [Contributor] The offending PR and associated issue have been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake.

      Link to the comment on the PR: https://github.com/Expensify/App/pull/57923/changes#r4245309263

    • [Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.

      Link to discussion: N/A

    • [Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.

      N/A - no reliable ways to reproduce this one

    Do we agree 👍 or 👎

  15. added
    Awaiting PaymentAuto-added when associated PR is deployed to production
    and removed on Oct 12, 2026
  16. melvin-bot commented on Oct 12, 2026

    @melvin-bot

    Triggered auto assignment to @mallenexpensify (Awaiting Payment)

  17. melvin-bot commented on Oct 12, 2026

    @melvin-bot

    Payment Summary

    Resolving PRs:

    Upwork Job

    • Assignee: @Eskalifer1 requires payment (Needs manual offer from BZ)

    BugZero Checklist (@mallenexpensify)

    • I have confirmed assignees, roles, and Upwork contracts look correct
    • I have paid out Upwork contracts / manual NewDot requests
    • [BugZero Assignee] I have created a GH issue for creating/updating the regression test once above steps have been agreed upon
  18. Eskalifer1 commented on Oct 14, 2026

    @Eskalifer1
    Contributor

    Note about payment: I'm getting paid via Upwork

  19. mallenexpensify commented on Oct 15, 2026

    @mallenexpensify
    Contributor

    Payment Summary

    Contributor+: @Eskalifer1 due $175 via Upwork

    @Eskalifer1 can you please accept the job below? Please reply here and tag me once you have.
    https://www.upwork.com/jobs/~022105713368630484716

  20. Eskalifer1 commented on Oct 15, 2026

    @Eskalifer1
    Contributor

    Hi @mallenexpensify, i have accepted, thank you!

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

Metadata

Metadata

Labels

Awaiting PaymentAuto-added when associated PR is deployed to productionBugSomething is broken. Auto assigns a BugZero manager.DailyKSv2ExternalAdded to denote the issue can be worked on by a contributorNeeds ReproductionReproducible steps needed

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions