Skip to content

Fetch requests with different ArrayBuffer bodies are cached under the same key #76326

Closed

Description

@rwalisa

Link to the code that reproduces this issue

https://github.com/rwalisa/nextjs-arraybuffer-post-bug-demo

To Reproduce

  1. Run next dev, in which POST requests are not cached by default
  2. Navigating between different pages under /continents shows different sets of countries, logs the continent correctly
  3. Run next build, which causes fetch to cache POST requests
  4. All continent pages use the same data, all log entries report the same continent

(Only the continent page sends GraphQL queries as ArrayBuffers, other pages use graphql-request which is cached correctly.)

Current vs. Expected behavior

SSG forces POST requests to be cached, under a different key for each POST body. However it can only serialize ReadableStream, Blob, FormData/URLSearchParams or string bodies, but not ArrayBuffer:

if (init.body) {
// handle ReadableStream body
if (typeof (init.body as any).getReader === 'function') {
const readableBody = init.body as ReadableStream<Uint8Array | string>
const chunks: Uint8Array[] = []
try {
await readableBody.pipeTo(
new WritableStream({
write(chunk) {
if (typeof chunk === 'string') {
chunks.push(encoder.encode(chunk))
bodyChunks.push(chunk)
} else {
chunks.push(chunk)
bodyChunks.push(decoder.decode(chunk, { stream: true }))
}
},
})
)
// Flush the decoder.
bodyChunks.push(decoder.decode())
// Create a new buffer with all the chunks.
const length = chunks.reduce((total, arr) => total + arr.length, 0)
const arrayBuffer = new Uint8Array(length)
// Push each of the chunks into the new array buffer.
let offset = 0
for (const chunk of chunks) {
arrayBuffer.set(chunk, offset)
offset += chunk.length
}
;(init as any)._ogBody = arrayBuffer
} catch (err) {
console.error('Problem reading body', err)
}
} // handle FormData or URLSearchParams bodies
else if (typeof (init.body as any).keys === 'function') {
const formData = init.body as FormData
;(init as any)._ogBody = init.body
for (const key of new Set([...formData.keys()])) {
const values = formData.getAll(key)
bodyChunks.push(
`${key}=${(
await Promise.all(
values.map(async (val) => {
if (typeof val === 'string') {
return val
} else {
return await val.text()
}
})
)
).join(',')}`
)
}
// handle blob body
} else if (typeof (init.body as any).arrayBuffer === 'function') {
const blob = init.body as Blob
const arrayBuffer = await blob.arrayBuffer()
bodyChunks.push(await blob.text())
;(init as any)._ogBody = new Blob([arrayBuffer], { type: blob.type })
} else if (typeof init.body === 'string') {
bodyChunks.push(init.body)
;(init as any)._ogBody = init.body
}
}
. This causes issues when using the SurrealDB JS client, which sends all its requests encoded as ArrayBuffers.

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #26~22.04.1-Ubuntu SMP Thu Jul 11 22:33:04 UTC 2024
  Available memory (MB): 15982
  Available CPU cores: 4
Binaries:
  Node: 20.2.0
  npm: 9.6.6
  Yarn: 1.22.22
  pnpm: 10.4.1
Relevant Packages:
  next: 15.2.0-canary.67 // Latest available version is detected (15.2.0-canary.67).
  eslint-config-next: 15.2.0-canary.67
  react: 19.1.0-canary-32b0cad8-20250213
  react-dom: 19.1.0-canary-32b0cad8-20250213
  typescript: 5.7.2
Next.js Config:

Which area(s) are affected? (Select all that apply)

Not sure

Which stage(s) are affected? (Select all that apply)

next build (local)

Additional context

No response

Activity

  1. added theissue type on Feb 21, 2025
  2. added a commit that references this issue on Feb 21, 2025
    0d5e855
  3. rwalisa commented on Mar 15, 2025

    @rwalisa
    Author

    This seems to be affecting HMR as well. Whenever I edit a page, the results of SurrealDB queries executed in the layout get mixed up with those from page queries and lead to errors.

    I'm not sure if layout cache can be turned off, the only workaround I could find is doing the following:

    import { fetch as undiciFetch } from "undici";
    
    async function runQuery(id: string): Promise<string> {
      const _f = fetch;
      globalThis.fetch = undiciFetch;
    
      const [result] = await db.query<[string]>(...);
    
      globalThis.fetch = _f
      return result;
    }
  4. marcoshernanz commented on Aug 12, 2026

    @marcoshernanz
    Contributor

    Thanks for the report and repro! This was fixed by #96008 and released in Next.js 15.5.21 and 16.2.11.

    I confirmed the repro fails on 15.5.20/16.2.10 and passes on 15.5.21/16.2.11 and current canary. Closing as fixed. #76327 is superseded by the byte-exact fix in #96008.

  5. rwalisa commented on Aug 12, 2026

    @rwalisa
    Author

    Cool, thank you!

  6. github-actions commented on Sep 6, 2026

    @github-actions
    Contributor

    This closed issue has been automatically locked because it had no new activity for 2 weeks. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

  7. locked as resolved and limited conversation to collaborators on Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions