Agent skill
debugging-websocket-issues
Use when seeing WebSocket errors like "Invalid frame header", "RSV1 must be clear", or "WS_ERR_UNEXPECTED_RSV_1" - covers multiple WebSocketServer conflicts, compression issues, and raw frame debugging techniques
Install this agent skill to your Project
npx add-skill https://github.com/aiskillstore/marketplace/tree/main/skills/agentworkforce/debugging-websocket-issues
SKILL.md
Debugging WebSocket Issues
Overview
WebSocket "invalid frame header" errors often stem from raw HTTP being written to an upgraded socket, not actual frame corruption. The most common cause is multiple WebSocketServer instances conflicting on the same HTTP server.
When to Use
- Error:
Invalid WebSocket frame: RSV1 must be clear - Error:
WS_ERR_UNEXPECTED_RSV_1 - Error:
Invalid frame header - WebSocket connects then immediately disconnects with code 1006
- Server logs success but client receives garbage data
Quick Reference
| Symptom | Likely Cause | Fix |
|---|---|---|
| RSV1 must be clear | Multiple WSS on same server OR compression mismatch | Use noServer: true mode |
Hex starts with 48545450 |
Raw HTTP on WebSocket (0x48='H') | Check for conflicting upgrade handlers |
| Code 1006, no reason | Abnormal closure, often server-side abort | Check abortHandshake calls |
| Works isolated, fails in app | Something else writing to socket | Audit all upgrade listeners |
The Multiple WebSocketServer Bug
Problem
When attaching multiple WebSocketServer instances to the same HTTP server using the server option:
// ❌ BAD - Both servers add upgrade listeners, causing conflicts
const wss1 = new WebSocketServer({ server, path: '/ws' });
const wss2 = new WebSocketServer({ server, path: '/ws/other' });
What happens:
- Client connects to
/ws - BOTH upgrade handlers fire (Node.js EventEmitter calls all listeners)
wss1matches path, handles upgrade successfullywss2doesn't match, callsabortHandshake(socket, 400)- Raw
HTTP/1.1 400 Bad Requestwritten to the now-WebSocket socket - Client receives HTTP text as WebSocket frame data
- First byte
0x48('H') interpreted as: RSV1=1, opcode=8 → invalid frame
Solution
Use noServer: true and manually route upgrades:
// ✅ GOOD - Single upgrade handler routes to correct server
const wss1 = new WebSocketServer({ noServer: true, perMessageDeflate: false });
const wss2 = new WebSocketServer({ noServer: true, perMessageDeflate: false });
server.on('upgrade', (request, socket, head) => {
const pathname = new URL(request.url || '', `http://${request.headers.host}`).pathname;
if (pathname === '/ws') {
wss1.handleUpgrade(request, socket, head, (ws) => {
wss1.emit('connection', ws, request);
});
} else if (pathname === '/ws/other') {
wss2.handleUpgrade(request, socket, head, (ws) => {
wss2.emit('connection', ws, request);
});
} else {
socket.destroy();
}
});
Debugging Techniques
Raw Frame Inspection
Hook into the socket to see actual bytes received:
ws.on('open', () => {
const socket = ws._socket;
const originalPush = socket.push.bind(socket);
socket.push = function(chunk, encoding) {
if (chunk) {
console.log('First 20 bytes (hex):', chunk.slice(0, 20).toString('hex'));
const byte0 = chunk[0];
console.log(`FIN: ${!!(byte0 & 0x80)}, RSV1: ${!!(byte0 & 0x40)}, Opcode: ${byte0 & 0x0f}`);
// Check if it's actually HTTP text
if (chunk.slice(0, 4).toString() === 'HTTP') {
console.log('*** RECEIVED RAW HTTP ON WEBSOCKET ***');
}
}
return originalPush(chunk, encoding);
};
});
Key Hex Patterns
81= FIN + text frame (normal)82= FIN + binary frame (normal)88= FIN + close frame (normal)48545450= "HTTP" - raw HTTP on WebSocket (bug!)c1or similar with bit 6 set = compressed frame (RSV1=1)
Common Mistakes
| Mistake | Result | Fix |
|---|---|---|
Multiple WSS with server option |
HTTP 400 written to socket | Use noServer: true |
perMessageDeflate: true (default in older ws) |
RSV1 set on frames | Explicitly set perMessageDeflate: false |
| Not checking upgrade headers | Miss compression negotiation | Log sec-websocket-extensions header |
| Assuming RSV1 error = compression | Could be raw HTTP | Check if bytes decode as ASCII "HTTP" |
Verification Checklist
After fixing, verify:
-
RSV1: falsein frame inspection -
Extensions header: NONEin upgrade response - No
HTTP/1.1in raw frame data - Messages received match sent payload size
- Multiple broadcasts work (test interval sends)
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
perigon-backend
Perigon ASP.NET Core + EF Core + Aspire conventions
perigon-agent
Pointers for Copilot/agents to apply Perigon conventions
perigon-angular
Angular 21+ standalone/Material/signal conventions for Perigon WebApp
fastapi-mastery
Comprehensive FastAPI development skill covering REST API creation, routing, request/response handling, validation, authentication, database integration, middleware, and deployment. Use when working with FastAPI projects, building APIs, implementing CRUD operations, setting up authentication/authorization, integrating databases (SQL/NoSQL), adding middleware, handling WebSockets, or deploying FastAPI applications. Triggered by requests involving .py files with FastAPI code, API endpoint creation, Pydantic models, or FastAPI-specific features.
context7-efficient
Token-efficient library documentation fetcher using Context7 MCP with 86.8% token savings through intelligent shell pipeline filtering. Fetches code examples, API references, and best practices for JavaScript, Python, Go, Rust, and other libraries. Use when users ask about library documentation, need code examples, want API usage patterns, are learning a new framework, need syntax reference, or troubleshooting with library-specific information. Triggers include questions like "Show me React hooks", "How do I use Prisma", "What's the Next.js routing syntax", or any request for library/framework documentation.
browser-use
Browser automation using Playwright MCP. Navigate websites, fill forms, click elements, take screenshots, and extract data. Use when tasks require web browsing, form submission, web scraping, UI testing, or any browser interaction.
Didn't find tool you were looking for?