Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Reading from a socket gets stuck on Node.js 26

Aperta Adatta ai principianti
#3,793 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 3 giorni

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
72/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
node.js, scala
Ambito
networking

Direzione di ricerca

Inizia con il test di riproduzione descritto per IoPlatformSuite, poi segui il codice readable-stream di Scala.js che chiama read() quando si verifica l’evento 'readable' di Node. Aggiungi un test di regressione per i chunk bufferizzati e verifica che legga tutti i dati su Node.js 26, rimanendo compatibile con le versioni precedenti di Node.js.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

bug

On Node.js 26, socket.reads can stop returning data even though the data has arrived. It works on Node.js 25 and earlier.

  • fs2-io 3.14.0, also on main (419d575)
  • cats-effect 3.7.1
  • Scala 2.13 and 3.3.7
  • Scala.js 1.22.0, Node.js 26.13.0, macOS
  • JVM and Native are fine
How to reproduce

This test, added to IoPlatformSuite, puts three pieces of data in a stream and reads them. On Node.js 26 it times out after getting only the first piece:

test("reads every chunk already buffered in a Readable") {
  def readable = {
    val duplex = new facade.stream.Duplex(
      new facade.stream.DuplexOptions {
        var autoDestroy = false
        var read = _ => ()
        var write = (_, _, _, _) => ()
        var `final` = (_, _) => ()
        var destroy = (_, _, _) => ()
      }
    )
    List[Byte](0, 1, 2).foreach(b => duplex.push(Chunk(b, b).toUint8Array))
    duplex
  }

  Stream
    .resource(suspendReadableAndRead[IO, Duplex]()(readable))
    .flatMap(_._2)
    .take(6)
    .compile
    .toList
    .timeout(1.second)
    .assertEquals(List[Byte](0, 0, 1, 1, 2, 2))
}

You can also see it with a real socket:

//> using scala 3.3.7
//> using platform scala-js
//> using jsVersion 1.22.0
//> using jsModuleKind common
//> using dep co.fs2::fs2-io::3.14.0

import cats.effect.{IO, IOApp, Resource}
import com.comcast.ip4s.*
import fs2.io.net.Network

import scala.concurrent.duration.*
import scala.scalajs.js

object Main extends IOApp.Simple {
  private val net = js.Dynamic.global.require("net")

  // sends 8 bytes three times, 50ms apart, then stays quiet
  private val server: Resource[IO, Int] =
    Resource.make(IO.async_[js.Dynamic] { cb =>
      val s = net.createServer { (socket: js.Dynamic) =>
        socket.write("aaaaaaaa")
        js.timers.setTimeout(50)(socket.write("bbbbbbbb"))
        js.timers.setTimeout(100)(socket.write("cccccccc"))
        ()
      }
      s.listen(0, "127.0.0.1", () => cb(Right(s)))
    })(s => IO(s.close()).void).map(_.address().port.asInstanceOf[Int])

  val run: IO[Unit] =
    server.use { port =>
      Network[IO].connect(SocketAddress(ipv4"127.0.0.1", Port.fromInt(port).get)).use { socket =>
        // wait until all 24 bytes have arrived, then read them
        IO.sleep(500.millis) >>
          socket.reads.chunks
            .evalTap(chunk => IO.println(s"  got ${chunk.size} bytes"))
            .flatMap(fs2.Stream.chunk)
            .take(24)
            .compile
            .count
            .timeout(3.seconds)
            .attempt
            .flatMap {
              case Right(n) => IO.println(s"Node ${js.Dynamic.global.process.version}: read all $n bytes")
              case Left(_)  => IO.println(s"Node ${js.Dynamic.global.process.version}: got stuck, the rest never came")
            }
      }
    }
}

On Node.js 26:

  got 8 bytes
  got 8 bytes
Node v26.13.0: got stuck, the rest never came

On Node.js 25 (same on 24 and 22):

  got 8 bytes
  got 16 bytes
Node v25.9.0: read all 24 bytes
Why

Node.js 26 changed readable.read(): it now returns one piece of the buffered data at a time, where it used to return all of it (nodejs/node#60441).

fs2 calls read() once each time Node fires 'readable'. Node only fires 'readable' again once everything has been read or more data comes in. So on Node.js 26, if nothing else comes in, the rest of the data is never read.

Fix

Keep calling read() until it returns null. On older Node.js versions the first call already returns everything, so nothing changes. PR to follow.

Lingua principale
Scala
Stelle
2.5k
Fork
633
Merge medio
4g 16h
PR unite (30g)
5

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di typelevel/fs2

Tutte le issue di typelevel/fs2

Issue simili

Altre issue su Scala

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.