Skip to content

[$250] Attachment - Csv file uploaded with other files is not shown in chat #80993

Closed

Description

@jponikarchuk

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: V9.3.11-15
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-3846/folder/13176710/41236953/1156875326
Email or phone of affected tester (no customers): dreamnitethedragon+yydyd373@gmail.com
Issue reported by: Applause Internal Team
Bug source: Exploratory - Significant User Experience Deterioration
Device used: Redminote 10S Android 13
App Component: Chat Report View

Action Performed:

  1. Launch app
  2. Tap plus icon - attachment
  3. Select a CSV file and an image
  4. Send attachments
  5. Note in preview only image is shown and csv file is missing

Expected Result:

Csv file uploaded with other files must be shown in chat

Actual Result:

Csv file uploaded with other files is not shown in chat but shown in preview.

Workaround:

Unknown

Platforms:

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

Screenshots/Videos

Bug7061718_1769762755027.Screenrecorder-2026-01-30-14-13-44-459.mp4

CSV_0.csv

View all open jobs on GitHub

Issue OwnerCurrent Issue Owner: @truph01
Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~022029613321483038734
  • Upwork Job ID: 2029613321483038734
  • Last Price Increase: 2026-03-12

Activity

  1. mkzie2 commented on Jan 30, 2026

    @mkzie2
    Contributor

    Proposal

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

    Csv file uploaded with other files is not shown in chat but shown in preview.

    What is the root cause of that problem?

    validateImageForCorruption immediately resolves if the file is not image:

    if (!Str.isImage(file.name ?? '') || !file.uri) {
    return Promise.resolve();
    }

    Then for csv files - the file size is usually very small (<240 bytes), isFileCorrupted will return result as invalid here:

    if (fileObject.size && fileObject.size < CONST.API_ATTACHMENT_VALIDATIONS.MIN_SIZE) {
    return {
    isValid: false,
    error: 'tooSmall',
    } satisfies AttachmentCorruptionValidationResult;
    }

    Then "invalid" csv files will be filtered out here, and not displayed:

    if (Array.isArray(result)) {
    const validResults = result.filter((r) => r.isValid);
    if (validResults.length === 0) {
    return;
    }
    const validatedFiles = validResults.map((r) => r.file);
    const firstValidSource = validResults.at(0)?.source;
    setSource(firstValidSource);
    setValidFiles(validatedFiles);
    return;
    }

    If we send only csv files, all files will be marked as "invalid", and the logic above returns early, so the validFiles is not changed. So the csv files are shown in that case.

    const [validFiles, setValidFiles] = useState<FileObject | FileObject[] | undefined>(fileParam);

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

    isFileCorrupted only checks for image integrity, so we should return early here if the file is not image:

        if (!Str.isImage(fileObject.name ?? '')) {
            return Promise.resolve({isValid: true});
        }

    We can place that logic before here

    return validateImageForCorruption(fileObject)

    Or before here

    if (fileObject.size && fileObject.size > CONST.API_ATTACHMENT_VALIDATIONS.MAX_SIZE) {

    Or we only check the image logic in the minimum size calculation and leave the max size check as-is:

    if (Str.isImage(fileObject.name ?? '') && fileObject.size && fileObject.size < CONST.API_ATTACHMENT_VALIDATIONS.MIN_SIZE) {

    if (fileObject.size && fileObject.size < CONST.API_ATTACHMENT_VALIDATIONS.MIN_SIZE) {

    What alternative solutions did you explore? (Optional)

    N/A

    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.

  2. cosmicvulpes commented on Jan 30, 2026

    @cosmicvulpes
    Contributor

    Proposal

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

    When uploading a CSV file together with other files (like images), the CSV file is not displayed in the chat message, while the image appears correctly. The CSV file is visible in the preview, but once sent, only the image shows in the chat.

    What is the root cause of that problem?

    The root cause is in the isReportMessageAttachment function at src/libs/isReportMessageAttachment.ts.

    When attachments are uploaded:

    1. Each attachment gets its own report action with HTML representing the file
    2. For images, the HTML is an <img> tag and the text is [Attachment]
    3. For non-image files (CSV, PDF, etc.), the HTML is an <a> tag and the text is the filename (e.g., "CSV_0.csv")

    The isReportMessageAttachment function checks:

    • If text === "[Attachment]" → return true
    • Else if Str.isVideo(text) → return true
    • Otherwise → return false

    For CSV files where text = "CSV_0.csv", both conditions fail, so the function returns false. This causes the fragment to render as TextCommentFragment (plain text filename) instead of AttachmentCommentFragment (clickable attachment with proper rendering).

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

    Modify isReportMessageAttachment to return true for any message that has the data-expensify-source attribute in its HTML, regardless of the text content. The presence of this attribute is the definitive marker that content is an Expensify attachment.

    The fix simplifies the logic:

    1. If HTML doesn't contain data-expensify-source → return false
    2. If it does contain the attribute → return true

    This ensures all attachment types (images, videos, CSV, PDF, etc.) are properly recognized and rendered as attachments.

    What alternative solutions did you explore? (Optional)

    N/A

  3. added
    BugSomething is broken. Auto assigns a BugZero manager.
    on Mar 5, 2026
  4. 27 remaining items

  5. JmillsExpensify commented on Mar 16, 2026

    @JmillsExpensify
    Contributor

    @truph01 there you go

  6. truph01 commented on Apr 2, 2026

    @truph01
    Contributor

    @MelvinBot, please create PR to fix this issue

  7. MelvinBot commented on Apr 2, 2026

    @MelvinBot
    Contributor

    🤖 After investigating, it appears this bug has already been fixed on main by PR #70740 (attachment validation refactor, merged March 18).

    What changed: The isFileCorrupted function that applied the MIN_SIZE check to all files was removed. The validation logic was restructured into src/libs/validateAttachmentFile.ts, where the MIN_SIZE check is now properly guarded:

    if (isValidatingReceipts && file.size < CONST.API_ATTACHMENT_VALIDATIONS.MIN_SIZE) {

    For regular chat attachments, isValidatingReceipts is false (set explicitly in useAttachmentUploadValidation and defaulted in ReportAddAttachmentModalContent), so the MIN_SIZE check is skipped entirely for non-receipt uploads. This means small CSV files are no longer silently rejected when uploaded alongside images.

    My existing PR (#85345) has merge conflicts because the code it modified no longer exists on main. Since the fix is already in place, that PR is now obsolete.

    Suggested next step: Please verify on the latest build that uploading a CSV + image together in chat works correctly. If the bug is still reproducible on the latest version, please let me know and I'll investigate further.

  8. truph01 commented on Apr 2, 2026

    @truph01
    Contributor

    @JmillsExpensify, This issue was fixed by another PR. Could you ask for a retest here?

    Screen.Recording.2026-04-02.at.15.56.45.mov
  9. JmillsExpensify commented on Apr 6, 2026

    @JmillsExpensify
    Contributor

    Done. I asked in Slack.

  10. IuliiaHerets commented on Apr 6, 2026

    @IuliiaHerets

    Issue is not reproducible on Web (Mac Chrome) and Android (SG-A54 - Android 16), v9.3.52-8

    2026-04-06.5.41.00.PM.mp4
    Screen.Recording.2026-04-06.at.5.34.41.PM.mov
  11. JmillsExpensify commented on Apr 6, 2026

    @JmillsExpensify
    Contributor

    @truph01 let me know if you are due payment for this issue.

  12. truph01 commented on Apr 6, 2026

    @truph01
    Contributor

    @JmillsExpensify I believe I should be eligible for payment, as I reviewed the PR and the issue was subsequently resolved in a different PR.

  13. JmillsExpensify commented on Apr 6, 2026

    @JmillsExpensify
    Contributor

    Payment summary: $250 @truph01 for PR proposal and reviews.

  14. JmillsExpensify commented on Apr 6, 2026

    @JmillsExpensify
    Contributor

    Agreed, that makes sense to me. Payment summary above.

  15. garrettmknight commented on May 10, 2026

    @garrettmknight
    Contributor

    $250 approved for @truph01

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.ExternalAdded to denote the issue can be worked on by a contributorReviewingHas a PR in reviewWeeklyKSv2

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions