Skip to main content
GoodFirstPicks
DashboardIssuesReposLeaderboard

GoodFirstPicks by Leaveitblank © 2026

CreatorRequest a RepoPrivacy PolicyTerms of Service
net: tryReadStart destroys socket on UV_EALREADY instead of ignoring it | GoodFirstPicks

net: tryReadStart destroys socket on UV_EALREADY instead of ignoring it

nodejs/node 0 comments 8d ago
View on GitHub
mediumopenScope: somewhat clearSkill match: maybeTest focusedNode.jsJavaScript

Why this is a good first issue

The issue involves handling UV_EALREADY in socket operations, requiring careful changes to avoid unintended destruction.

AI Summary

The issue occurs when `tryReadStart()` destroys a socket upon receiving `UV_EALREADY` from `readStart()`, which should be ignored instead. This happens in specific scenarios involving multiple `readStart` calls in the same microtask batch. The fix requires modifying `tryReadStart()` to handle `UV_EALREADY` appropriately without destroying the socket.

Issue Description

Version

v26.0.0-pre (main branch, also affects v24.12.0)

Platform

Linux 6.12.73+deb13-amd64 x86_64

Subsystem

net

What steps will reproduce the bug?

tryReadStart() in lib/net.js destroys the socket when readStart() returns UV_EALREADY. This can be reproduced by calling readStart when reading is already active at the libuv level:

const net = require('net');
const { internalBinding } = require('internal/test/binding');
const { UV_EALREADY } = internalBinding('uv');

const server = net.createServer((conn) => { conn.on('error', () => {}); });
server.listen('/tmp/test-ealready.sock', () => {
  const socket = net.createConnection({ path: '/tmp/test-ealready.sock' });
  socket.on('connect', () => {
    // Simulate readStart returning UV_EALREADY (happens with sockets
    // opened via uv_pipe_open where reading is already active)
    socket._handle.readStart = () => UV_EALREADY;
    socket._handle.reading = false;
    socket._read(16384);

    // Socket is now destroyed even though reading was already active
    console.log('destroyed:', socket.destroyed); // true
    socket.destroy();
  });
  socket.on('error', (e) => console.log('error:', e.code)); // EALREADY
  socket.on('close', () => server.close());
});

In practice, this happens when socket types with no async connect phase (synchronous bind, 'connect' emitted via nextTick) cause multiple readStart calls in the same microtask batch. Discovered while implementing AF_CAN socket support (#62398), but the bug is in tryReadStart itself.

How often does it reproduce? Is there a required condition?

100% reproducible. The condition is readStart() returning UV_EALREADY, which occurs when:

  • A socket fd is opened via uv_pipe_open() and readStart is called more than once
  • The deferred _read callback (queued while connecting=true) and the stream resume() from a 'data' listener both fire in the same tick

What is the expected behavior? W

Want to work on this?

Claim this issue to let others know you're working on it. You'll earn 20 points when you complete it!

Risk Flags

  • requires understanding of libuv internals
  • potential impact on socket handling
Loading labels...

Details

Points20 pts
Difficultymedium
Scopesomewhat clear
Skill Matchmaybe
Test Focusedyes