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

  1. Use a wisp server that only sends DATA on client-initiated streams (check server version/implementation)
  2. Handle server-initiated streams by registering a connection entry when an unknown stream ID first appears instead of throwing
  3. Ensure stream close is acknowledged and the server stops sending before deleting this.connections[stream_id] on the client
  4. 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

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


AI-assisted analysis of copy/v86@180830d539 (2026-08-31). Data as JSON: /api/errors/50d65be778514232. Report an issue: GitHub.