BloopAI/vibe-kanban · error

Enrollment code must be 6 characters.

Error message

Enrollment code must be 6 characters.

What it means

startSpake2Enrollment validates that the normalized enrollment code is exactly ENROLLMENT_CODE_LENGTH (6) alphanumeric characters before using it as the SPAKE2 password; otherwise it throws. This is a client-side input guard preventing pointless PAKE handshakes.

Source

Thrown at packages/web-core/src/shared/lib/relayPake.ts:45

  passwordBytes: Uint8Array;
  passwordScalar: bigint;
  xScalar: bigint;
  clientMessageBytes: Uint8Array;
}

export function normalizeEnrollmentCode(rawCode: string): string {
  return rawCode
    .trim()
    .toUpperCase()
    .replace(/[^A-Z0-9]/g, '');
}

export async function startSpake2Enrollment(
  rawEnrollmentCode: string
): Promise<{ state: Spake2EnrollmentClientState; clientMessageB64: string }> {
  const enrollmentCode = normalizeEnrollmentCode(rawEnrollmentCode);
  if (enrollmentCode.length !== ENROLLMENT_CODE_LENGTH) {
    throw new Error('Enrollment code must be 6 characters.');
  }

  const passwordBytes = ENCODER.encode(enrollmentCode);
  const passwordScalar = await hashToSpake2Scalar(passwordBytes);
  const xScalar = randomScalar();

  const clientPoint = ed25519.ExtendedPoint.BASE.multiply(xScalar).add(
    SPAKE2_M.multiply(passwordScalar)
  );
  const clientPointBytes = clientPoint.toRawBytes();

  const clientMessage = new Uint8Array(1 + clientPointBytes.length);
  clientMessage[0] = 0x41; // 'A'
  clientMessage.set(clientPointBytes, 1);

  return {
    state: {
      passwordBytes,

View on GitHub (pinned to 4deb7eca8f)

Solutions

  1. Validate/measure normalizeEnrollmentCode(input) client-side before invoking and show a form error.
  2. Prompt the user to re-enter the exact 6-character code from the host display.
  3. Strip surrounding formatting (spaces, hyphens) — normalization already handles it, but length must still be 6 after stripping.
  4. If codes come from an API/QR, confirm the generator emits exactly 6 A-Z0-9 characters.

Example fix

// before
await startSpake2Enrollment(codeInput);
// after
const code = normalizeEnrollmentCode(codeInput);
if (code.length !== 6) {
  setError('Pairing code must be exactly 6 letters/digits.');
  return;
}
await startSpake2Enrollment(code);
Defensive patterns

Strategy: validation

Validate before calling

import { normalizeEnrollmentCode } from '@/shared/lib/relayPake';
const code = normalizeEnrollmentCode(userInput);
if (code.length !== 6) {
  setError('Enter the 6-character code shown on the host.');
  return;
}

Type guard

function isValidEnrollmentCode(s: string): boolean {
  return /^[A-Z0-9]{6}$/.test(s.trim().toUpperCase());
}

Try / catch

if (!isValidEnrollmentCode(userInput)) {
  setError('Pairing code must be exactly 6 letters/digits.');
  return;
}
try {
  await startSpake2Enrollment(userInput);
} catch (e) { showError(e); }

Prevention

When it happens

Trigger: Calling startSpake2Enrollment with a code that, after normalizeEnrollmentCode (trim, uppercase, strip non-A-Z0-9), is not 6 chars — e.g. empty input, partially typed code, code containing only invalid characters, or a 7+ character paste.

Common situations: User mistypes the 6-character pairing code shown on the host; copying a code with extra whitespace/characters that get stripped leaving fewer than 6; calling the function programmatically with a placeholder like '------' (dashes stripped → 0 chars).

Related errors


AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29). Data as JSON: /api/errors/5254b53c480afd51. Report an issue: GitHub.