You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Due for payment 2026-05-29] [$250] Expenses - Unable to save the expense description field blank when it's required #88707
Version Number: 9.3.62-1 Reproducible in staging?: Yes Reproducible in production?: Yes 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:@puneetlath Slack conversation (hyperlinked to channel name): #expensify_bugs
The validate function in IOURequestStepDescription.tsx:107-122 unconditionally blocks form submission when the description is required and empty. It doesn't account for the "no changes" case.
The updateComment handler (line 147) correctly handles unchanged values by early-returning and navigating back — but FormProvider calls validatebeforeonSubmit, so that early-return is never reached when the description is blank and required.
What changes do you think we should make in order to solve the problem?
In the validate callback in IOURequestStepDescription.tsx, skip the isDescriptionRequired check when the current value matches the original description (currentDescriptionInMarkdown). If the user hasn't changed anything, validation should not block saving.
The check at line 115 should be updated to also verify the comment has actually changed from the original before enforcing the required-field rule:
if (isDescriptionRequired && !values.moneyRequestComment && values.moneyRequestComment !== currentDescriptionInMarkdown)
This way, if the description was already blank and the user didn't change it, the form submits normally and the existing early-return in updateComment navigates back as expected.
What alternative solutions did you explore? (Optional)
An alternative would be to bypass FormProvider validation entirely when the value is unchanged (e.g., a custom shouldValidate prop). However, that would be a larger change to the shared form infrastructure. The targeted fix in validate is simpler, scoped to this page, and preserves existing behavior for all other cases.
updateComment (which has the unchanged-value early-return at line 147) is never called
isDescriptionRequired source:CategoryUtils.ts:129-134 — returns true when the category has areCommentsRequired and policy rules are enabled.
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.
Please re-state the problem that we are trying to solve in this issue.
On a Control workspace whose category has the "Description required" rule enabled, when a user opens an existing expense and taps the description menu item, the description step screen opens with the current (possibly empty) value pre-filled. Tapping Save without typing anything should simply close the step and return the user to the expense view — the description edit screen is not the place where a missing-description rule is enforced, that already happens on the expense/confirmation level via the missingComment violation. Today, the Save button surfaces a "This field is required" error on the input and blocks the user from leaving the step, even though nothing was changed.
What is the root cause of that problem?
The description step's form has two independent mechanisms that together are inconsistent:
The form's onSubmit handler has an early return that already short-circuits the "nothing changed" case — if the trimmed submitted value equals the value the user opened the screen with, it just flips isSaved and navigates back without touching Onyx:
The form's validate callback, added when the "Description required" category rule landed, unconditionally flags the required error whenever the description is required for the category and the submitted value is empty — it never looks at what the user actually started with:
Because FormProvider runs validate before calling onSubmit, the required-field error fires and the no-change shortcut in updateComment is never reached. As a result, any expense that already has an empty description (created before the rule was enabled, or whose category was changed after the fact, or simply opened to inspect it) becomes impossible to leave via Save — the user has to use the back arrow instead, which defeats the purpose of the Save button.
The enforcement of the actual "description is required" policy rule lives in ViolationsUtils.getViolationsOnyxData and already surfaces a workspace-level violation on the expense regardless of whether the user saves a blank description, so relaxing this form-level guard only for the no-change path does not bypass the rule:
What changes do you think we should make in order to solve the problem?
In src/pages/iou/request/step/IOURequestStepDescription.tsx, make the validate callback consistent with the existing no-change shortcut in updateComment by skipping the required-field error when the submitted value is unchanged from currentDescriptionInMarkdown (both the current value that was displayed in the input and, after trimming, the submitted value). Concretely, inside validate, compute the trimmed submitted value once, and only add the common.error.fieldRequired error when the category requires a description AND the trimmed submitted value is empty AND the trimmed submitted value differs from currentDescriptionInMarkdown. Add currentDescriptionInMarkdown to the useCallback dependency array.
This aligns the validator with the already-present "no-op save = navigate back" behavior in updateComment and keeps the character-limit check unchanged. It also leaves the case "user actively cleared a non-empty description on a required category" correctly rejected — in that case, the submitted value is empty but differs from the stored non-empty value, so the required error still fires.
Creation flow is unaffected: when the category has the rule and the user reaches this step during manual expense creation, the stored description (the value used for the unchanged comparison) is empty, and if the user submits empty, the submitted trimmed value equals the stored empty value — validation would pass here, but the missing description is then caught on the confirmation list where isDescriptionRequired is already wired into the submit guard:
What alternative solutions did you explore? (Optional)
An alternative was to move the required check out of the form validator entirely and into updateComment so that it runs after the no-change early return. That works but it splits validation between two places and loses the automatic inline error UX that FormProvider gives for free on the character-limit check — a user who did clear a required description would no longer see the red inline hint under the input, only a generic alert. Keeping the check in validate and simply widening its condition to value-is-empty AND value-changed-from-original preserves both UX paths with a minimal, local change.
changed the title [-]Expenses - Unable to save the expense description field blank when it's required[/-][+][$250] Expenses - Unable to save the expense description field blank when it's required[/+]on Apr 24, 2026
@mallenexpensify it is visible now and I’ve already applied for it before. So it says you’ve already submitted your proposal, could you take a look please?
Activity
MelvinBot commentedon Apr 24, 2026
Proposal
What is the root cause of that problem?
The
validatefunction inIOURequestStepDescription.tsx:107-122unconditionally blocks form submission when the description is required and empty. It doesn't account for the "no changes" case.The
updateCommenthandler (line 147) correctly handles unchanged values by early-returning and navigating back — butFormProvidercallsvalidatebeforeonSubmit, so that early-return is never reached when the description is blank and required.What changes do you think we should make in order to solve the problem?
In the
validatecallback inIOURequestStepDescription.tsx, skip theisDescriptionRequiredcheck when the current value matches the original description (currentDescriptionInMarkdown). If the user hasn't changed anything, validation should not block saving.The check at line 115 should be updated to also verify the comment has actually changed from the original before enforcing the required-field rule:
This way, if the description was already blank and the user didn't change it, the form submits normally and the existing early-return in
updateCommentnavigates back as expected.What alternative solutions did you explore? (Optional)
An alternative would be to bypass
FormProvidervalidation entirely when the value is unchanged (e.g., a customshouldValidateprop). However, that would be a larger change to the shared form infrastructure. The targeted fix invalidateis simpler, scoped to this page, and preserves existing behavior for all other cases.Investigation details
Data flow:
FormProvidercallsvalidatebeforeonSubmitvalidatechecksisDescriptionRequired(true) &&!values.moneyRequestComment(true) → returns errorupdateComment(which has the unchanged-value early-return at line 147) is never calledisDescriptionRequiredsource:CategoryUtils.ts:129-134— returns true when the category hasareCommentsRequiredand policy rules are enabled.Next Steps for Contributor+ team: Reply with
@MelvinBot implement thisto create a draft PR,@MelvinBot <your feedback>to refine this analysis, or explain why you are rejecting Melvin's proposal.melvin-bot commentedon Apr 24, 2026
Triggered auto assignment to Contributor-plus team member for initial proposal review - @gijoe0295 (
External)wildan-m commentedon Apr 24, 2026
Proposal
Please re-state the problem that we are trying to solve in this issue.
On a Control workspace whose category has the "Description required" rule enabled, when a user opens an existing expense and taps the description menu item, the description step screen opens with the current (possibly empty) value pre-filled. Tapping Save without typing anything should simply close the step and return the user to the expense view — the description edit screen is not the place where a missing-description rule is enforced, that already happens on the expense/confirmation level via the
missingCommentviolation. Today, the Save button surfaces a "This field is required" error on the input and blocks the user from leaving the step, even though nothing was changed.What is the root cause of that problem?
The description step's form has two independent mechanisms that together are inconsistent:
onSubmithandler has an early return that already short-circuits the "nothing changed" case — if the trimmed submitted value equals the value the user opened the screen with, it just flipsisSavedand navigates back without touching Onyx:App/src/pages/iou/request/step/IOURequestStepDescription.tsx
Lines 138 to 142 in 620eeaa
validatecallback, added when the "Description required" category rule landed, unconditionally flags the required error whenever the description is required for the category and the submitted value is empty — it never looks at what the user actually started with:App/src/pages/iou/request/step/IOURequestStepDescription.tsx
Lines 113 to 115 in 620eeaa
Because
FormProviderrunsvalidatebefore callingonSubmit, the required-field error fires and the no-change shortcut inupdateCommentis never reached. As a result, any expense that already has an empty description (created before the rule was enabled, or whose category was changed after the fact, or simply opened to inspect it) becomes impossible to leave via Save — the user has to use the back arrow instead, which defeats the purpose of the Save button.The enforcement of the actual "description is required" policy rule lives in
ViolationsUtils.getViolationsOnyxDataand already surfaces a workspace-level violation on the expense regardless of whether the user saves a blank description, so relaxing this form-level guard only for the no-change path does not bypass the rule:App/src/libs/Violations/ViolationsUtils.ts
Lines 527 to 528 in 620eeaa
What changes do you think we should make in order to solve the problem?
In
src/pages/iou/request/step/IOURequestStepDescription.tsx, make thevalidatecallback consistent with the existing no-change shortcut inupdateCommentby skipping the required-field error when the submitted value is unchanged fromcurrentDescriptionInMarkdown(both the current value that was displayed in the input and, after trimming, the submitted value). Concretely, insidevalidate, compute the trimmed submitted value once, and only add thecommon.error.fieldRequirederror when the category requires a description AND the trimmed submitted value is empty AND the trimmed submitted value differs fromcurrentDescriptionInMarkdown. AddcurrentDescriptionInMarkdownto theuseCallbackdependency array.This aligns the validator with the already-present "no-op save = navigate back" behavior in
updateCommentand keeps the character-limit check unchanged. It also leaves the case "user actively cleared a non-empty description on a required category" correctly rejected — in that case, the submitted value is empty but differs from the stored non-empty value, so the required error still fires.Compare branch: https://github.com/Expensify/App/compare/main...wildan-m:App:wildan/88707-allow-no-change-save-on-required-description?expand=1
Creation flow is unaffected: when the category has the rule and the user reaches this step during manual expense creation, the stored description (the value used for the unchanged comparison) is empty, and if the user submits empty, the submitted trimmed value equals the stored empty value — validation would pass here, but the missing description is then caught on the confirmation list where
isDescriptionRequiredis already wired into the submit guard:App/src/components/MoneyRequestConfirmationList.tsx
Lines 428 to 432 in 620eeaa
What alternative solutions did you explore? (Optional)
An alternative was to move the required check out of the form validator entirely and into
updateCommentso that it runs after the no-change early return. That works but it splits validation between two places and loses the automatic inline error UX thatFormProvidergives for free on the character-limit check — a user who did clear a required description would no longer see the red inline hint under the input, only a generic alert. Keeping the check invalidateand simply widening its condition tovalue-is-empty AND value-changed-from-originalpreserves both UX paths with a minimal, local change.melvin-bot commentedon Apr 24, 2026
Job added to Upwork: https://www.upwork.com/jobs/~022047731679436458961
[-]Expenses - Unable to save the expense description field blank when it's required[/-][+][$250] Expenses - Unable to save the expense description field blank when it's required[/+]65 remaining items
mallenexpensify commentedon Jun 1, 2026
@karan-1302 can you please accept the job below? Please reply here and tag me once you have.
https://www.upwork.com/jobs/~022060466163242179232
Thx
karan-1302 commentedon Jun 3, 2026
@mallenexpensify It says that the job is no longer available. Please take a look
mallenexpensify commentedon Jun 3, 2026
@karan-1302 can you check again plz? Upwork's been having issues lately. I'm seeing on my end
https://www.upwork.com/jobs/~022060466163242179232
karan-1302 commentedon Jun 4, 2026
@mallenexpensify it is visible now and I’ve already applied for it before. So it says you’ve already submitted your proposal, could you take a look please?
mallenexpensify commentedon Jun 4, 2026
@karan-1302 you need to accept the offer in Upwork in order for me to hire and pay. It's still showing 'pending'. Maybe see if this link works/helps?
https://www.upwork.com/nx/wm/offer/111594726
karan-1302 commentedon Jun 5, 2026
@mallenexpensify done.
mallenexpensify commentedon Jun 5, 2026
@karan-1302 paid, summary updated above. Thx.
JmillsExpensify commentedon Jun 5, 2026
$250 approved for @gijoe0295