{"record":{"id":"50d65be778514232","repo":"copy/v86","slug":"got-a-data-packet-but-stream-not-registered-id","errorCode":null,"errorMessage":"Got a DATA packet but stream not registered. ID: ","messagePattern":"Got a DATA packet but stream not registered\\. ID: ","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/browser/wisp_network.js","lineNumber":89,"sourceCode":"            this.connections[stream_id].congested = true;\n            this.congested_buffer.push({data: data, type: type});\n        }\n    }\n};\n\nWispNetworkAdapter.prototype.process_incoming_wisp_frame = function(frame) {\n    const view = new DataView(frame.buffer);\n    const stream_id = view.getUint32(1, true);\n    switch(frame[0]) {\n        case 1: // CONNECT\n            // The server should never send this actually\n            dbg_log(\"Server sent client-only packet CONNECT\", LOG_NET);\n            break;\n        case 2: // DATA\n            if(this.connections[stream_id])\n                this.connections[stream_id].data_callback(frame.slice(5));\n            else\n                throw new Error(\"Got a DATA packet but stream not registered. ID: \" + stream_id);\n            break;\n        case 3: // CONTINUE\n            if(this.connections[stream_id]) {\n                this.connections[stream_id].congestion = view.getUint32(5, true);\n            }\n\n            if(this.connections[stream_id].congested) {\n                const buffer = this.congested_buffer.slice(0);\n                this.congested_buffer.length = 0;\n                this.connections[stream_id].congested = false;\n                for(const packet of buffer) {\n                    this.send_packet(packet.data, packet.type, stream_id);\n                }\n            }\n            break;\n        case 4: // CLOSE\n            if(this.connections[stream_id])\n                this.connections[stream_id].close_callback(view.getUint8(5));","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/copy/v86/blob/180830d539dcc87db1a191febf6c914f516d102f/src/browser/wisp_network.js#L71-L107","documentation":"The WispClient routes incoming frames by type; a DATA frame (type 2) must correspond to a stream ID previously registered in this.connections (one the client itself opened). Receiving DATA for an unknown stream ID means the server is sending data for a stream this client doesn't know, so it throws rather than silently dropping bytes.","triggerScenarios":"Server sends a DATA frame whose stream_id has no entry in this.connections — e.g. streams created by the server side (server-initiated streams), a client restart/reload while the old server-side session persists, or a client bug that deleted the connection entry (e.g. on close) before remaining DATA frames arrived.","commonSituations":"Page reload mid-transfer leaving stale server streams sending data to a fresh client; connecting to a non-standard or buggy wisp server that reuses stream IDs; race where the client removes the connection on stream close but the server still has in-flight DATA frames.","solutions":["Use a wisp server that only sends DATA on client-initiated streams (check server version/implementation)","Handle server-initiated streams by registering a connection entry when an unknown stream ID first appears instead of throwing","Ensure stream close is acknowledged and the server stops sending before deleting this.connections[stream_id] on the client","Wrap handle_incoming_packet in try/catch per-frame so one stale DATA frame doesn't kill the whole client"],"exampleFix":"// before\ncase 2:\n    if(this.connections[stream_id])\n    this.connections[stream_id].data_callback(frame.slice(5));\n    else\n    throw new Error(\"Got a DATA packet but stream not registered. ID: \" + stream_id);\n// after\ncase 2:\n    if(this.connections[stream_id]) {\n    this.connections[stream_id].data_callback(frame.slice(5));\n    } else {\n    dbg_log(\"DATA for unknown stream \" + stream_id + \", ignoring\", LOG_NET);\n    // optionally send CLOSE for stream_id\n    }","handlingStrategy":"type-guard","validationCode":"function streamIsRegistered(client, streamId) {\n    return Object.prototype.hasOwnProperty.call(client.connections, streamId);\n}\n// before feeding frames:\nif (frameType === 2 && !streamIsRegistered(client, streamId)) ignoreOrCloseStream(streamId);","typeGuard":"function hasStream(client, id) {\n    return typeof id === \"number\" && client.connections[id] != null;\n}","tryCatchPattern":"try {\n    client.handle_incoming_packet(frame);\n} catch (e) {\n    if (e.message.startsWith(\"Got a DATA packet but stream not registered\")) {\n    dbg_log(\"stale DATA frame ignored\", LOG_NET);\n    } else throw e;\n}","preventionTips":["Run a wisp server that never sends DATA on unknown/server-initiated streams","Don't delete connection entries until the stream is fully closed and ACKed","Reload-safe: on client restart, send CLOSE for stale stream IDs","Catch per-frame so one bad frame doesn't tear down the client"],"tags":["network","websocket","wisp","protocol"],"backgroundTag":"unknown-stream-id","analyzedSha":"180830d539dcc87db1a191febf6c914f516d102f","analyzedAt":"2026-08-31T22:39:37.599Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}