Skip to content

ERR_INVALID_STATE when canceling during nested Suspense #4769

@gaearon

Description

@gaearon

What version of Hono are you using?

4.12.2

What runtime/platform is your app running on? (with version if possible)

Node

What steps can reproduce the bug?

I think it's the same error as honojs/node-server#233 but according to Claude, the actual bug is upstream here. Failing test:

  it('should not throw ERR_INVALID_STATE when reader is cancelled during nested Suspense streaming', async () => {
    const unhandled: unknown[] = []
    const onRejection = (e: unknown) => unhandled.push(e)
    process.on('unhandledRejection', onRejection)

    try {
      const SubContent = () => {
        const content = new Promise<HtmlEscapedString>((resolve) =>
          setTimeout(() => resolve(<h2>World</h2>), 50)
        )
        return content
      }

      const Content = () => {
        const content = new Promise<HtmlEscapedString>((resolve) =>
          setTimeout(
            () =>
              resolve(
                <>
                  <h1>Hello</h1>
                  <Suspense fallback={<p>Loading sub...</p>}>
                    <SubContent />
                  </Suspense>
                </>
              ),
            20
          )
        )
        return content
      }

      const onError = vi.fn()
      const stream = renderToReadableStream(
        <Suspense fallback={<p>Loading...</p>}>
          <Content />
        </Suspense>,
        onError
      )

      const reader = stream.getReader()
      const firstChunk = await reader.read()
      expect(firstChunk.done).toBe(false)

      // Simulate client disconnect
      await reader.cancel()

      // Wait for nested Suspense callbacks to fire against the closed controller
      await new Promise((resolve) => setTimeout(resolve, 200))

      expect(unhandled).toHaveLength(0)
    } finally {
      process.off('unhandledRejection', onRejection)
      suspenseCounter++
    }
  })

What is the expected behavior?

No crashing

What do you see instead?

Crashing

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions