App icon indicating copy to clipboard operation
App copied to clipboard

[$250] Expense - Expense amount is changed after creating track expense with 8 digits distance

Open lanitochka17 opened this issue 1 month ago • 10 comments

If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!


Version Number: V9.2.75-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/TR-2349/folder/18717689/49756688/1068908483?sort=%2Bstatus_id Email or phone of affected tester (no customers): [email protected] Issue reported by: Applause Internal Team Bug source: Regression TC Execution Device used: Redminote 10S Android 13 App Component: Money Requests

Action Performed:

  1. Launch app
  2. Open 1:1 chat
  3. Create track manual distance expense with 8 digits distance eg: 77777777

Expected Result:

Expense amount must not be changed after creating track expense with 8 digits distance.

Actual Result:

Expense amount is changed after creating track expense with 8 digits distance.

Workaround:

Unknown

Platforms:

  • [x] Android: App
  • [ ] Android: mWeb Chrome
  • [ ] iOS: App
  • [ ] iOS: mWeb Safari
  • [ ] iOS: mWeb Chrome
  • [x] Windows: Chrome
  • [ ] MacOS: Chrome / Safari

Screenshots/Videos

https://github.com/user-attachments/assets/809c55ec-5927-4e6a-a2c0-43a9427ab73b

View all open jobs on GitHub

Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~022000925389099432331
  • Upwork Job ID: 2000925389099432331
  • Last Price Increase: 2025-12-23
Issue OwnerCurrent Issue Owner: @abdulrahuman5196

lanitochka17 avatar Dec 11 '25 16:12 lanitochka17

Triggered auto assignment to @sonialiap (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

melvin-bot[bot] avatar Dec 11 '25 16:12 melvin-bot[bot]

Proposal

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

Expense amount is changed after creating track expense with 8 digits distance.

What is the root cause of that problem?

We are passing the amountMaxLength as 14 for the distance request here

https://github.com/Expensify/App/blob/8df157ee61a823a95e9bf9a1992af99ccb345f59/src/components/MoneyRequestConfirmationList.tsx#L940-L943

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

We should remove CONST.IOU.DISTANCE_REQUEST_AMOUNT_MAX_LENGTH to use default value amountMaxLength (8)

                if (isDistanceRequest && !isDistanceRequestWithPendingRoute && !validateAmount(String(iouAmount), decimals))   {
                    setFormError('common.error.invalidAmount');
                    return;
                }

Or we'll only delete it if it's a manual distance request

                 if (isDistanceRequest && !isDistanceRequestWithPendingRoute && !validateAmount(String(iouAmount), decimals, isManualDistanceRequest ? undefined : CONST.IOU.DISTANCE_REQUEST_AMOUNT_MAX_LENGTH)) {
                    setFormError('common.error.invalidAmount');
                    return;
                }

https://github.com/Expensify/App/blob/8df157ee61a823a95e9bf9a1992af99ccb345f59/src/components/MoneyRequestConfirmationList.tsx#L940-L943

https://github.com/Expensify/App/blob/50f5b59dcf82c65269e276a5cf4a8cd1313991fc/src/libs/MoneyRequestUtils.ts#L44-L48

What alternative solutions did you explore? (Optional)

Or we can check the amount and throw the error if the value > 21474836 like we did here

https://github.com/Expensify/App/blob/bd180d78952816a042f7a763c99b021e784e92b0/src/pages/workspace/expensifyCard/WorkspaceEditCardLimitPage.tsx#L120-L123

Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.

daledah avatar Dec 11 '25 16:12 daledah

Proposal

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

Expense amount is changed after creating track expense with 8 digits distance

What is the root cause of that problem?

When creating a manual distance expense with 8-digit distances (e.g., 77,777,777 miles), the calculated expense amount overflows and is clamped to 21,474,836.47 instead of the correct value. The issue is an integer overflow in getDistanceRequestAmount(), which computes Math.round(roundedDistance * rate). For example, 77,777,777 miles × 70 cents = 5,444,444,390 cents. The backend stores amounts as 32-bit signed integers with a maximum of 2,147,483,647 (2³¹ - 1), so this value exceeds the limit.

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

We should prevent integer overflow. Backend uses 32-bit signed integers, so we should clamp to maximum value. In this way they value will be clamped in frontend too and will be consistent with backend. We should change getDistanceRequestAmount and Clamped to MAX_32_BIT_SIGNED_INT to prevent integer overflow https://github.com/Expensify/App/blob/864e7a349e16a9d3ab11ea25e0298460b5b4a747/src/libs/DistanceRequestUtils.ts#L265-L268

  const convertedDistance = convertDistanceUnit(distance, unit);
    const roundedDistance = parseFloat(convertedDistance.toFixed(2));
    const calculatedAmount = Math.round(roundedDistance * rate);
    return Math.min(calculatedAmount, CONST.IOU.MAX_32_BIT_SIGNED_INT);

And in const file add MAX_32_BIT_SIGNED_INT: 2147483647.

https://github.com/user-attachments/assets/f4522147-23fa-436f-ab85-1ecc88417612

What alternative solutions did you explore? (Optional)

Here we can through error if iouAmount > CONST.IOU.MAX_32_BIT_SIGNED_INT https://github.com/Expensify/App/blob/780c623bfbdfae3341faafccb64ad39ed81f6f2a/src/components/MoneyRequestConfirmationList.tsx#L940-L943

   if (isDistanceRequest && !isDistanceRequestWithPendingRoute) {
                    if (!validateAmount(String(iouAmount), decimals, CONST.IOU.DISTANCE_REQUEST_AMOUNT_MAX_LENGTH)) {
                        setFormError('common.error.invalidAmount');
                        return;
                    }
                    
                    // Check if amount exceeds 32-bit signed integer maximum to prevent integer overflow
                    if (iouAmount > CONST.IOU.MAX_32_BIT_SIGNED_INT) {
                        setFormError('iou.error.invalidAmount' as TranslationPaths);
                        return;
                    }
                }

Nodebrute avatar Dec 11 '25 20:12 Nodebrute

Proposal

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

Creating a manual distance expense with an 8-digit distance (e.g., 77,777,777) shows a wrong amount.

What is the root cause of that problem?

We calculate the distance amount with Math.round(roundedDistance * rate) and then send it to the server, but the server stores amounts as 32-bit signed integers. Large distances overflow that limit, so the backend clamps to the max int and the amount changes. We do not guard this on the client. https://github.com/Expensify/App/blob/0c92ee767ee420c5ba4cb50a1ed9e0695c4f2077/src/libs/DistanceRequestUtils.ts#L262-L269 and https://github.com/Expensify/App/blob/0c92ee767ee420c5ba4cb50a1ed9e0695c4f2077/src/components/MoneyRequestConfirmationList.tsx#L939-L945

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

Stop overflow by clamping and validating before submiting, with a clear error.

Updated code

// DistanceRequestUtils.ts
const MAX_32_BIT_SIGNED_INT = 2_147_483_647;

function getDistanceRequestAmount(distance: number, unit: Unit, rate: number): number {
    const convertedDistance = convertDistanceUnit(distance, unit);
    const roundedDistance = parseFloat(convertedDistance.toFixed(2));
    const calculatedAmount = Math.round(roundedDistance * rate);
    return Math.min(calculatedAmount, MAX_32_BIT_SIGNED_INT);
}
// MoneyRequestConfirmationList.tsx (validation before submit)
if (isDistanceRequest && !isDistanceRequestWithPendingRoute) {
    const exceedsMax = iouAmount > CONST.IOU.MAX_32_BIT_SIGNED_INT;
    if (!validateAmount(String(iouAmount), decimals, CONST.IOU.DISTANCE_REQUEST_AMOUNT_MAX_LENGTH) || exceedsMax) {
        setFormError('iou.error.invalidAmount');
        return;
    }
}

We can also add unit test for the same.

ShridharGoel avatar Dec 13 '25 15:12 ShridharGoel

Job added to Upwork: https://www.upwork.com/jobs/~022000925389099432331

melvin-bot[bot] avatar Dec 16 '25 13:12 melvin-bot[bot]

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

melvin-bot[bot] avatar Dec 16 '25 13:12 melvin-bot[bot]

@abdulrahuman5196 Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

melvin-bot[bot] avatar Dec 20 '25 00:12 melvin-bot[bot]

checking now

abdulrahuman5196 avatar Dec 23 '25 12:12 abdulrahuman5196

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

melvin-bot[bot] avatar Dec 23 '25 16:12 melvin-bot[bot]

@sonialiap @abdulrahuman5196 this issue was created 2 weeks ago. Are we close to approving a proposal? If not, what's blocking us from getting this issue assigned? Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!

melvin-bot[bot] avatar Dec 25 '25 21:12 melvin-bot[bot]

@abdulrahuman5196 Whoops! This issue is 2 days overdue. Let's get this updated quick!

melvin-bot[bot] avatar Dec 27 '25 00:12 melvin-bot[bot]

@abdulrahuman5196 what do you think of the proposals?

sonialiap avatar Dec 30 '25 12:12 sonialiap

@sonialiap could you kindly reapply the C+ label? So that another C+ can take it. I am currently unavailable to check this.

abdulrahuman5196 avatar Dec 30 '25 12:12 abdulrahuman5196

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

melvin-bot[bot] avatar Dec 30 '25 12:12 melvin-bot[bot]

Thanks for letting me know @abdulrahuman5196 :)

sonialiap avatar Dec 30 '25 12:12 sonialiap

@bernhardoj we have a few proposals to review, what do you think?

sonialiap avatar Dec 30 '25 12:12 sonialiap

Will check this tomorrow..

bernhardoj avatar Dec 30 '25 15:12 bernhardoj

📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸

melvin-bot[bot] avatar Dec 30 '25 16:12 melvin-bot[bot]

@daledah @Nodebrute @ShridharGoel Is this still happening? I can create the distance expense with an amount larger than the OP.

Image

bernhardoj avatar Dec 31 '25 04:12 bernhardoj