Skip to content

cache.match not working after cache.add #5859

Open

Description

@kjsik11

Bug Description

cache.match() and cache.matchAll() failed with TypeError [ERR_INVALID_STATE]: Invalid state: ReadableStream is locked when used after cache.add() and cache.addAll()

  1. cache.add(url)
    cache.match(url) -> error

  2. cache.addAll([url])
    cache.matchAll() -> error

Reproduction

Need to run on 8.11.0

  1. mkdir repro && cd repro (outside the undici repo)
  2. npm i undici@8.11.0
  3. save the code('repro.js') to repro dir
  4. node --test repro.js
'use strict'

const { test } = require('node:test')
const { createServer } = require('node:http')
const { once } = require('node:events')
const { caches } = require('undici')

async function startServer (t) {
  const server = createServer((_, res) => res.end('hello')).listen(0)
  t.after(() => server.close())
  await once(server, 'listening')
  return `http://localhost:${server.address().port}`
}

test('cache.match() after cache.add()', { timeout: 5000 }, async (t) => {
  const base = await startServer(t)
  const cache = await caches.open('hello')

  await cache.add(`${base}/hello`)

  const response = await cache.match(`${base}/hello`)
  t.assert.strictEqual(await response.text(), 'hello')
})

test('cache.matchAll() after cache.addAll()', { timeout: 5000 }, async (t) => {
  const base = await startServer(t)
  const cache = await caches.open('world')

  await cache.addAll([`${base}/world`])

  const responses = await cache.matchAll()
  t.assert.strictEqual(responses.length, 1)
})

same failure showed in WPT: node test/web-platform-tests/wpt-runner.mjs run /service-workers/cache-storage/cache-add

Expected Behavior

cache.match(url) returns the cached response

Actual Behavior

cache.match() and cache.matchAll() reject:

TypeError [ERR_INVALID_STATE]: Invalid state: ReadableStream is locked
    at setupReadableStreamDefaultReader (node:internal/webstreams/readablestream:2565:11)
    at new ReadableStreamDefaultReader (node:internal/webstreams/readablestream:918:5)
    at readableByteStreamTee (node:internal/webstreams/readablestream:1935:16)
    at readableStreamTee (node:internal/webstreams/readablestream:1819:12)
    at ReadableStreamTee (node:stream/web:55:10)
    at cloneBody (node_modules/undici/lib/web/fetch/body.js:290:51)
    at cloneResponse (node_modules/undici/lib/web/fetch/response.js:358:24)
    at cloneResponse (node_modules/undici/lib/web/fetch/response.js:347:7)
    at #internalMatchAll (node_modules/undici/lib/web/cache/cache.js:798:48)
    at Cache.match (node_modules/undici/lib/web/cache/cache.js:52:37) {
  code: 'ERR_INVALID_STATE'
 }

Environment

  • OS: macOS 26.6.2
  • Node.js version: v24.20.0
  • undici version: 8.11.0

Activity

  1. Sarthak-Shreshtha01 commented on Sep 26, 2026

    @Sarthak-Shreshtha01

    In cache.add/addAll I replace the used-up body of the fetched response with a new body built from the bytes that were read, so the stored response can be copied again by cache.match and cache.matchAll. (PR: #5911)

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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions