{"record":{"id":"f1d1d69f8ff7c884","repo":"schollz/croc","slug":"peer-message-did-not-include-a-type","errorCode":null,"errorMessage":"Peer message did not include a type","messagePattern":"Peer message did not include a type","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/protocol/codec.ts","lineNumber":45,"sourceCode":"  if (message.m) wire.m = message.m;\n  if (message.b?.byteLength) wire.b = bytesToBase64(message.b);\n  if (message.b2?.byteLength) wire.b2 = bytesToBase64(message.b2);\n  if (message.n) wire.n = message.n;\n  let bytes = await wasm.compress(textEncoder.encode(JSON.stringify(wire)));\n  if (key) bytes = await wasm.encrypt(bytes, key);\n  return bytes;\n}\n\nexport async function decodeMessage(\n  wasm: CrocWasm,\n  payload: Uint8Array,\n  key?: Uint8Array,\n) {\n  let bytes = payload;\n  if (key) bytes = await wasm.decrypt(bytes, key);\n  bytes = await wasm.decompress(bytes, MAX_FRAME_SIZE);\n  const wire = JSON.parse(textDecoder.decode(bytes)) as WireMessage;\n  if (!wire.t) throw new Error(\"Peer message did not include a type\");\n  return {\n    t: wire.t,\n    v: wire.v,\n    m: wire.m,\n    b: wire.b ? base64ToBytes(wire.b) : undefined,\n    b2: wire.b2 ? base64ToBytes(wire.b2) : undefined,\n    n: wire.n,\n  } satisfies CrocMessage;\n}\n","sourceCodeStart":27,"sourceCodeEnd":55,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/codec.ts#L27-L55","documentation":"decodeMessage() decrypts, decompresses, and JSON-parses a peer message, then requires the parsed wire object to carry a truthy 't' (type) field. Every well-formed croc protocol message must be tagged with a type so the receiver can dispatch it. If the JSON decodes but 't' is absent, null, or empty, the message is considered malformed and rejected.","triggerScenarios":"Calling decodeMessage(wasm, payload, key) where payload decrypts/decompresses to valid JSON without a 't' property (e.g. {\"v\":1} or an unrelated JSON object). Happens when a peer sends an untyped message, a sender/receiver version mismatch changes the wire schema, or a test feeds hand-crafted JSON through the codec.","commonSituations":"Interop testing between the browser client and a non-standard/modified croc peer; protocol version drift after upgrading one side; unit tests that build fake peer messages and forget the 't' field; replaying captured frames with a wrong key that happens to yield valid JSON.","solutions":["Check what the peer actually sent: log the decoded JSON (before the throw) and confirm the message shape; well-formed croc messages always include a type such as 'pake', 'offer', or chunk data.","Verify both peers run compatible protocol versions; a peer omitting 't' is violating the wire contract and should be updated.","In tests, always include the 't' field when constructing WireMessage fixtures (e.g. { t: \"transfer\", v: 1 }).","If you control the sender, add the type tag before serializing/encrypting with encodeMessage."],"exampleFix":"// before (test fixture / peer)\nconst wire = { v: 1, b: base64 }; // missing type\n// after\nconst wire = { t: \"transfer\", v: 1, b: base64 };","handlingStrategy":"try-catch","validationCode":"function looksLikeTypedWire(json: string): boolean {\n  try {\n    const parsed = JSON.parse(json);\n    return typeof parsed?.t === \"string\" && parsed.t.length > 0;\n  } catch {\n    return false;\n  }\n}","typeGuard":"function isWireMessage(value: unknown): value is { t: string } {\n  return typeof value === \"object\" && value !== null &&\n    typeof (value as { t?: unknown }).t === \"string\" &&\n    (value as { t: string }).t.length > 0;\n}","tryCatchPattern":"try {\n  const msg = await decodeMessage(wasm, payload, key);\n  dispatch(msg);\n} catch (error) {\n  if (error instanceof Error && error.message === \"Peer message did not include a type\") {\n    // Malformed peer message: log and drop it, keep the connection alive\n    console.warn(\"dropping untyped peer message\");\n    return;\n  }\n  throw error;\n}","preventionTips":["Always include the 't' type field when constructing peer messages in tests or custom senders.","Keep both peers on compatible croc protocol versions before relaying messages.","Log the decoded-but-untyped payload once to identify which peer emits schema-violating messages."],"tags":["protocol","codec","peer-message","json"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}