{"record":{"id":"ede996b4441ad421","repo":"schollz/croc","slug":"relay-could-not-open-the-room-confirmation","errorCode":null,"errorMessage":"Relay could not open the room: ${confirmation}","messagePattern":"Relay could not open the room: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/protocol/client.ts","lineNumber":131,"sourceCode":"    const peer = await socket.receive();\n    const finished = await engine.pakeUpdate(pake.handle, peer);\n    const salt = randomBytes(8);\n    const key = await engine.deriveKey(finished.key, salt);\n    await socket.send(salt);\n    await socket.send(await engine.encrypt(textEncoder.encode(settings.relayPassword), key));\n    const response = textDecoder.decode(\n      await engine.decrypt(await socket.receive(), key),\n    );\n    const separator = response.indexOf(\"|||\");\n    if (separator < 0) throw new Error(`Relay rejected the connection: ${response}`);\n    const banner = response.slice(0, separator);\n    const externalIP = response.slice(separator + 3);\n    await socket.send(await engine.encrypt(textEncoder.encode(room), key));\n    const confirmation = textDecoder.decode(\n      await engine.decrypt(await socket.receive(), key),\n    );\n    if (confirmation !== \"ok\") {\n      throw new Error(`Relay could not open the room: ${confirmation}`);\n    }\n    return { socket, banner, externalIP } satisfies RelayConnection;\n  } catch (error) {\n    socket.close();\n    throw error;\n  }\n}\n\nasync function sendControl(\n  socket: CrocSocket,\n  message: CrocMessage,\n  key?: Uint8Array,\n) {\n  await socket.send(await encodeMessage(wasm(), message, key));\n}\n\nasync function receiveControl(socket: CrocSocket, key?: Uint8Array) {\n  return decodeMessage(wasm(), await socket.receive(), key);","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/client.ts#L113-L149","documentation":"After relay authentication the client sends the room identifier (derived from the transfer code) and expects the encrypted reply 'ok'. Any other confirmation string means the relay could not join or create that room, and the string is included in the message (commonly 'room full' or a similar reason). This guards the room-based rendezvous step before any peer communication starts.","triggerScenarios":"Three or more parties using the same code phrase so the room already has its two participants; relay limits on concurrent rooms; a relay whose room bookkeeping rejected the join.","commonSituations":"Reusing a short custom code while a previous transfer with the same code is still connected; retrying immediately after an aborted transfer before the relay times the old room out.","solutions":["Read the confirmation string in the message for the relay's stated reason","Use a fresh code phrase (regenerate rather than reusing a custom one) and retry","Wait a few seconds for the relay to reap the stale room, then reconnect"],"exampleFix":"// before: reusing the same custom room\nawait sendFiles({ files, secret: \"project-files\", settings }); // room occupied\n\n// after: unique code per transfer\nconst secret = await newCodePhrase(); // e.g. 'baker-glass-iron-leaf'\nawait sendFiles({ files, secret, settings });","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await sendFiles(opts);\n} catch (e) {\n  if (/could not open the room/.test(e.message) && attemptsLeft--) {\n    await delay(3000);            // let the relay reap the stale room\n    opts.secret = await newCode(); // fresh room\n    return sendFiles(opts);\n  }\n  throw e;\n}","preventionTips":["Use unique generated codes per transfer instead of fixed custom codes","Wait a few seconds before retrying the same code after an aborted transfer","Avoid three parties sharing one code phrase simultaneously"],"tags":["relay","room","handshake"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}