Why is my file attachment corrupted when uploading from an S3 signed URL buffer using createInvoiceAttachmentByFileName in Xero?
05:25 06 Aug 2025

I'm using Xero's createInvoiceAttachmentByFileName function to attach a file to an invoice. The file is stored in S3, so I first generate a pre-signed URL, fetch the file using that URL, convert the response into a buffer, and then pass that buffer into the Xero function.

The upload completes without errors, but when I download the attachment from Xero, the file is corrupted—it either fails to open or displays as raw buffer data.

Has anyone encountered this? Is there a specific encoding or buffer handling step I might be missing when working with signed S3 URLs and Xero's API?

My Code as below:

const downloadFileFromS3 = async (url) => {
    const res = await axios.get(url, { responseType: 'arraybuffer' });
    return Buffer.from(res.data);
};

const uploadSingleAttachment = async (tenantId, invoiceId, s3Url) => {
    await getTokenSet();
    const includeOnline = true;
    const idempotencyKey = uuidv4();
    
    const parsedUrl = new URL(s3Url?.file);
    const pathname = parsedUrl.pathname;
    const fileName = pathname.substring(pathname.lastIndexOf('/') + 1);
    const fileBuffer = await downloadFileFromS3(s3Url?.file);
    const mimeType = s3Url?.mimType;
    
    return await xero.accountingApi.createInvoiceAttachmentByFileName(
        tenantId,
        invoiceId,
        fileName,
        fileBuffer,
        includeOnline,
        idempotencyKey,
        {
            headers: {
                "Content-Type": mimeType
            }
        }
    );
};

Attachment has been uploaded using my above code but it's corrupted. It's should not corrupted.

invoice xero