{"record":{"id":"b242045f054133fa","repo":"stablyai/orca","slug":"invalid-label-expected-expected-bytes-got","errorCode":null,"errorMessage":"Invalid ${label}: expected ${expected} bytes, got ${bytes.length}","messagePattern":"Invalid (.+?): expected (.+?) bytes, got (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mobile/src/transport/mobile-e2ee-v2-key-schedule.ts","lineNumber":46,"sourceCode":"    desktopToMobileKey: expanded.slice(32, 64),\n    sessionId: expanded.slice(64, 96),\n    transcriptHash\n  }\n}\n\nfunction concatBytes(parts: readonly Uint8Array[]): Uint8Array {\n  const result = new Uint8Array(parts.reduce((total, part) => total + part.length, 0))\n  let offset = 0\n  for (const part of parts) {\n    result.set(part, offset)\n    offset += part.length\n  }\n  return result\n}\n\nfunction requireLength(bytes: Uint8Array, expected: number, label: string): void {\n  if (bytes.length !== expected) {\n    throw new Error(`Invalid ${label}: expected ${expected} bytes, got ${bytes.length}`)\n  }\n}\n","sourceCodeStart":28,"sourceCodeEnd":49,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/transport/mobile-e2ee-v2-key-schedule.ts#L28-L49","documentation":"Thrown by `requireLength` inside `deriveMobileE2EEV2KeySchedule` when the shared secret, client nonce, or desktop nonce is not exactly 32 bytes. The HKDF expansion assumes 32-byte inputs; a different length means an upstream cryptographic primitive returned the wrong size (e.g. a truncated X25519 shared secret or a nonce that was not generated by `expo-crypto.getRandomBytes(32)`).","triggerScenarios":"`acceptReady` invoked with a `handshake.clientNonce`/`handshake.desktopNonce` that is not 32 bytes; `deriveSharedKey` returning something other than 32 bytes due to a malformed public key; a key schedule test passing hand-rolled buffers of the wrong length.","commonSituations":"Corrupted or base64-decoded-with-wrong-alphabet nonce from the desktop; a pre-release desktop that sends 16-byte nonces; tests that hand-construct a handshake without respecting the 32-byte contract; a public key from `publicKeyFromBase64` that decoded to a non-32-byte scalar.","solutions":["Verify the desktop ready message decodes client/desktop nonces to exactly 32 bytes before calling `acceptReady`.","Confirm `deriveSharedKey` (X25519) is producing 32 bytes — check the pinned desktop public key is a valid 32-byte point.","Regenerate the client nonce via `ExpoCrypto.getRandomBytes(32)` rather than reusing a buffer of another length."],"exampleFix":"// before\nacceptReady({ ..., clientNonce: shortNonce, desktopNonce: shortNonce })\n// -> Invalid client nonce: expected 32 bytes, got 16\n\n// after\nconst clientNonce = ExpoCrypto.getRandomBytes(32)\n// validate desktopNonce length before acceptReady:\nif (handshake.desktopNonce.length !== 32) throw new Error('bad desktop nonce')","handlingStrategy":"validation","validationCode":"function validKeyScheduleInputs(sharedSecret: Uint8Array, clientNonce: Uint8Array, desktopNonce: Uint8Array): boolean {\n  return sharedSecret.length === 32 && clientNonce.length === 32 && desktopNonce.length === 32\n}\nif (!validKeyScheduleInputs(secret, cNonce, dNonce)) throw new Error('bad crypto lengths')","typeGuard":"function is32Bytes(b: Uint8Array): b is Uint8Array { return b.length === 32 }","tryCatchPattern":"try { deriveMobileE2EEV2KeySchedule({ sharedSecret, transcript, clientNonce, desktopNonce }) } catch (e) { if (e.message.startsWith('Invalid ')) { /* abort handshake, log which input was wrong size */ } else throw e }","preventionTips":["Generate nonces only via ExpoCrypto.getRandomBytes(32).","Validate the pinned desktop public key decodes to 32 bytes before pairing.","Reject handshakes whose decoded nonces are not 32 bytes upstream of acceptReady."],"tags":["crypto","validation","e2ee","key-schedule"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}