copy/v86 · error · Error
Got a DATA packet but stream not registered. ID:
Error message
Got a DATA packet but stream not registered. ID:
What it means
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.
Source
Thrown at src/browser/wisp_network.js:89
this.connections[stream_id].congested = true;
this.congested_buffer.push({data: data, type: type});
}
}
};
WispNetworkAdapter.prototype.process_incoming_wisp_frame = function(frame) {
const view = new DataView(frame.buffer);
const stream_id = view.getUint32(1, true);
switch(frame[0]) {
case 1: // CONNECT
// The server should never send this actually
dbg_log("Server sent client-only packet CONNECT", LOG_NET);
break;
case 2: // DATA
if(this.connections[stream_id])
this.connections[stream_id].data_callback(frame.slice(5));
else
throw new Error("Got a DATA packet but stream not registered. ID: " + stream_id);
break;
case 3: // CONTINUE
if(this.connections[stream_id]) {
this.connections[stream_id].congestion = view.getUint32(5, true);
}
if(this.connections[stream_id].congested) {
const buffer = this.congested_buffer.slice(0);
this.congested_buffer.length = 0;
this.connections[stream_id].congested = false;
for(const packet of buffer) {
this.send_packet(packet.data, packet.type, stream_id);
}
}
break;
case 4: // CLOSE
if(this.connections[stream_id])
this.connections[stream_id].close_callback(view.getUint8(5));View on GitHub (pinned to 180830d539)
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
Example fix
// before
case 2:
if(this.connections[stream_id])
this.connections[stream_id].data_callback(frame.slice(5));
else
throw new Error("Got a DATA packet but stream not registered. ID: " + stream_id);
// after
case 2:
if(this.connections[stream_id]) {
this.connections[stream_id].data_callback(frame.slice(5));
} else {
dbg_log("DATA for unknown stream " + stream_id + ", ignoring", LOG_NET);
// optionally send CLOSE for stream_id
} Defensive patterns
Strategy: type-guard
Validate before calling
function streamIsRegistered(client, streamId) {
return Object.prototype.hasOwnProperty.call(client.connections, streamId);
}
// before feeding frames:
if (frameType === 2 && !streamIsRegistered(client, streamId)) ignoreOrCloseStream(streamId); Type guard
function hasStream(client, id) {
return typeof id === "number" && client.connections[id] != null;
} Try / catch
try {
client.handle_incoming_packet(frame);
} catch (e) {
if (e.message.startsWith("Got a DATA packet but stream not registered")) {
dbg_log("stale DATA frame ignored", LOG_NET);
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- stream capacity overflow in GrowableRingbuffer.write(), pack
- pool of dynamic TCP port numbers exhausted, connection abort
- Unknown port for localhost: "%s"
AI-assisted analysis of copy/v86@180830d539 (2026-08-31).
Data as JSON: /api/errors/50d65be778514232.
Report an issue: GitHub.