Skip to content

base64Encode causes RangeError: Maximum call stack size exceeded #41

@mwohlan

Description

@mwohlan

Environment

Digital Ocean App Platform running Nuxt3 App

Reproduction

It runs fine locally, but crashes when deployed on more limited hardware

Describe the bug

Since I have not provided a reproduction, here is a detailed description of the issue:

I am using undio to transform uint8 Array to a Base64 encoded String ( first page of a pdf to pass it into an llm API).

 const pdf: ReadableStream = await graphClient.api(`/users/xxxxxx/drive/items/${pdfID}/content`).get()
    const firstPage = await extractFirstPageFromPdf(pdf)
    
    const base64 = uint8ArrayToBase64(firstPage, { dataURL: false })

This works fine locally but when deployed to DigitalOcean App Platform ( smallest resource size) the following error occurs when undio is calling the internal function _base64Encode:

function _base64Encode(data, opts) {
  let encoded = btoa(String.fromCodePoint(...data));
  if (opts?.urlSafe) {
    encoded = encoded.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
  }
  return opts?.dataURL === false ? encoded : `data:${opts?.type || ""};base64,${encoded}`;
}

RangeError: Maximum call stack size exceeded

This is explanation the o1-preview model provided:

The error you're encountering—"RangeError: Maximum call stack size exceeded"—is due to the way you're using the spread operator (...) with String.fromCodePoint() on a potentially large array of data. When data is large, spreading it as arguments to String.fromCodePoint() can exceed the maximum number of arguments that a function can accept, leading to a stack overflow.

I can't really judge if this is a valid explanation but the provided fix did work for my environment. But it is of course a Node only solution:

import { Buffer } from 'node:buffer'

export function uInt8ToBase64(data: Uint8Array, opts?: { urlSafe?: boolean, dataURL?: boolean, type?: string }) {
  let encoded = Buffer.from(data).toString('base64')
  if (opts?.urlSafe) {
    encoded = encoded.replace(/\+/g, '-').replace(/\//g, '').replace(/=+$/, '')
  }
  return opts?.dataURL === false ? encoded : `data:${opts?.type || ''};base64,${encoded}`
}

Additional context

No response

Logs

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions