Skip to main content
GoodFirstPicks
DashboardIssuesReposLeaderboard

GoodFirstPicks by Leaveitblank © 2026

CreatorRequest a RepoPrivacy PolicyTerms of Service
Assertion failure crash in TLSWrap::DoWrite with zombie HTTP/2 session (close event not propagated from OS-level CLOSED socket) | GoodFirstPicks

Assertion failure crash in TLSWrap::DoWrite with zombie HTTP/2 session (close event not propagated from OS-level CLOSED socket)

nodejs/node 1 comments 1mo ago
View on GitHub
highopenScope: somewhat clearSkill match: maybeTest focusedNode.jsJavaScript

Why this is a good first issue

Complex HTTP2/TLS socket state issue requiring deep protocol knowledge.

AI Summary

The issue involves an assertion failure in TLSWrap when handling zombie HTTP/2 sessions with closed sockets. Reproducing requires network manipulation and understanding of HTTP/2 session lifecycle. The main challenge is diagnosing the socket state propagation issue without breaking existing functionality.

Issue Description

Version

v22.13.1

Platform

Darwin 24.3.0 (macOS, arm64)

Subsystem

http2, tls

What steps will reproduce the bug?

Reproducible test case (requires sudo for firewall manipulation)

We created a test that simulates a network "black hole" using macOS pf firewall.

Prerequisites: Generate self-signed certificates in the same directory:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost"
// test-zombie.js - Reproduces Node.js HTTP/2 assertion failure
// Run with: sudo node test-zombie.js
//
// This triggers: Assertion failed: is_write_in_progress()
// in node::http2::Http2Session::OnStreamAfterWrite

const http2 = require('http2')
const { spawn, execSync } = require('child_process')

const PORT = 8444

async function main() {
    if (process.getuid() !== 0) {
        console.log('Run with: sudo node test-zombie.js')
        process.exit(1)
    }

    // Cleanup from previous runs
    try {
        execSync(`lsof -ti:${PORT} | xargs kill -9 2>/dev/null || true`)
        execSync('pfctl -a zombie_test -F all 2>/dev/null || true')
    } catch (e) {}
    await new Promise(r => setTimeout(r, 500))

    console.log('Node version:', process.version)
    console.log('PID:', process.pid)

    // Start server as child process
    const server = spawn('node', ['-e', `
        const http2 = require('http2')
        const fs = require('fs')
        const server = http2.createSecureServer({
            key: fs.readFileSync('./key.pem'),
            cert: fs.readFileSync('./cert.pem'),
        })
        server.on('stream', (s, h) => {
            s.respond({ ':status': 200 })
            s.end('ok')
        })
        server.listen(${PORT}, () => console.log('Server ready'))
        setInterval(() => {}, 10000)
    `], { stdio: ['ignore', 'pipe', 'pipe'] })

    server.stdout.on('data', d => console.log('[SERVER]', d.toString().trim()))
    server.stderr.on('data', d => console.log('[SERV

Want to work on this?

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

Risk Flags

  • requires root privileges
  • network manipulation
  • TLS/HTTP2 internals
Loading labels...

Details

Points10 pts
Difficultyhigh
Scopesomewhat clear
Skill Matchmaybe
Test Focusedyes