{"record":{"id":"547bea4cf3920fb2","repo":"BloopAI/vibe-kanban","slug":"invalid-enrollment-id","errorCode":null,"errorMessage":"Invalid enrollment ID.","messagePattern":"Invalid enrollment ID\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/web-core/src/shared/lib/relayPake.ts","lineNumber":267,"sourceCode":"    ['sign']\n  );\n  const signature = await crypto.subtle.sign('HMAC', key, toArrayBuffer(data));\n  return new Uint8Array(signature);\n}\n\nasync function sha256(data: Uint8Array): Promise<Uint8Array> {\n  const digest = await crypto.subtle.digest('SHA-256', toArrayBuffer(data));\n  return new Uint8Array(digest);\n}\n\nfunction toArrayBuffer(data: Uint8Array): ArrayBuffer {\n  return new Uint8Array(data).buffer;\n}\n\nfunction uuidToBytes(rawUuid: string): Uint8Array {\n  const hex = rawUuid.replace(/-/g, '');\n  if (hex.length !== 32) {\n    throw new Error('Invalid enrollment ID.');\n  }\n\n  const bytes = new Uint8Array(16);\n  for (let i = 0; i < 16; i += 1) {\n    const value = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);\n    if (Number.isNaN(value)) {\n      throw new Error('Invalid enrollment ID.');\n    }\n    bytes[i] = value;\n  }\n\n  return bytes;\n}\n\nfunction bytesToBigIntLE(bytes: Uint8Array): bigint {\n  let value = 0n;\n  for (let i = bytes.length - 1; i >= 0; i -= 1) {\n    value = (value << 8n) + BigInt(bytes[i]);","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/packages/web-core/src/shared/lib/relayPake.ts#L249-L285","documentation":"uuidToBytes converts a hyphen-stripped UUID hex string to 16 bytes and throws if the resulting hex is not exactly 32 characters — i.e. the input is not a well-formed UUID. Reached via enrollmentIdBytes when building enrollment request payloads.","triggerScenarios":"Calling enrollmentIdBytes/uuidToBytes with a non-UUID string: empty value, a short ID, a UUID with braces/urn: prefix that leaves non-hex residue, or a server-returned ID field that is undefined coerced to 'undefined' (10 chars).","commonSituations":"Host ID or enrollment ID not yet loaded (undefined) when the pairing request is constructed; backend returning a numeric or prefixed ID where the client expects a UUID; copy/paste of a display name instead of the UUID.","solutions":["Ensure the enrollment/host UUID is loaded (not undefined/null) before building the request.","Validate the string matches a UUID regex before calling.","Strip wrappers like urn:uuid: or {...} if your source produces them.","Log the raw value on failure to see what the server or UI actually supplied."],"exampleFix":"// before\nconst bytes = enrollmentIdBytes(enrollmentId); // may be undefined\n// after\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nif (!enrollmentId || !UUID_RE.test(enrollmentId)) {\n  throw new Error(`Bad enrollment id: ${enrollmentId}`);\n}\nconst bytes = enrollmentIdBytes(enrollmentId);","handlingStrategy":"validation","validationCode":"const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nif (!enrollmentId || !UUID_RE.test(enrollmentId)) {\n  throw new Error(`Invalid enrollment ID: ${enrollmentId}`);\n}","typeGuard":"function isUuid(v: unknown): v is string {\n  return typeof v === 'string' &&\n    /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(v);\n}","tryCatchPattern":"if (!isUuid(enrollmentId)) {\n  showError('Enrollment ID must be a valid UUID.');\n  return;\n}\ntry {\n  await beginEnrollment(enrollmentId);\n} catch (e) { handleError(e); }","preventionTips":["Never build requests until async-loaded IDs have resolved (check for undefined)","Strip urn:uuid:/{...} wrappers if your ID source emits them","Use the canonical UUID string exactly as the server returns it","Add a UUID regex check at the UI/boundary layer to fail early"],"tags":["validation","uuid","input"],"backgroundTag":"invalid-uuid-format","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}