[$250] Expense - Expense amount is changed after creating track expense with 8 digits distance
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:
- Launch app
- Open 1:1 chat
- 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
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 Owner
Current Issue Owner: @abdulrahuman5196
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.
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.
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;
}
}
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.
Job added to Upwork: https://www.upwork.com/jobs/~022000925389099432331
Triggered auto assignment to Contributor-plus team member for initial proposal review - @abdulrahuman5196 (External)
@abdulrahuman5196 Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!
checking now
📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸
@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!
@abdulrahuman5196 Whoops! This issue is 2 days overdue. Let's get this updated quick!
@abdulrahuman5196 what do you think of the proposals?
@sonialiap could you kindly reapply the C+ label? So that another C+ can take it. I am currently unavailable to check this.
Triggered auto assignment to Contributor-plus team member for initial proposal review - @bernhardoj (External)
Thanks for letting me know @abdulrahuman5196 :)
@bernhardoj we have a few proposals to review, what do you think?
Will check this tomorrow..
📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸
@daledah @Nodebrute @ShridharGoel Is this still happening? I can create the distance expense with an amount larger than the OP.