commaai/openpilot · error · RuntimeError

Confirmation code required but not provided

Error message

Confirmation code required but not provided

What it means

prepare_download() reads ccRequiredFlag from the server's smdpSigned2. When the flag is nonzero the SM-DP+ demands a confirmation code (the activation code's part after the '$$' in the QR, or one issued by the carrier). If the caller passed cc=None or an empty string in that case, RuntimeError is raised before any eUICC interaction.

Source

Thrown at openpilot/common/esim/lpa.py:507

    raise RuntimeError(f"AuthenticateServer rejected by eUICC: {AUTH_SERVER_ERROR_CODES.get(code, 'unknown')} (0x{code:02X})")
  return b64e(response)


def prepare_download(client: AtClient, b64_signed2: str, b64_sig2: str, b64_cert: str, cc: str | None = None) -> str:
  smdp_signed2 = b64d(b64_signed2)
  smdp_signature2 = b64d(b64_sig2)
  smdp_certificate = b64d(b64_cert)
  smdp_signed2_root = find_tag(smdp_signed2, 0x30)
  if smdp_signed2_root is None:
    raise RuntimeError("Invalid smdpSigned2")
  transaction_id = find_tag(smdp_signed2_root, TAG_STATUS)
  cc_required_flag = find_tag(smdp_signed2_root, 0x01)
  if transaction_id is None or cc_required_flag is None:
    raise RuntimeError("Invalid smdpSigned2")
  content = smdp_signed2 + smdp_signature2
  if int.from_bytes(cc_required_flag, "big") != 0:
    if not cc:
      raise RuntimeError("Confirmation code required but not provided")
    content += encode_tlv(0x04, hashlib.sha256(hashlib.sha256(cc.encode("utf-8")).digest() + transaction_id).digest())
  content += smdp_certificate
  response = es10x_command(client, encode_tlv(TAG_PREPARE_DOWNLOAD, content))
  require_tag(response, TAG_PREPARE_DOWNLOAD, "PrepareDownloadResponse")
  return b64e(response)


def _parse_tlv_header_len(data: bytes) -> int:
  tag_len = 2 if data[0] & 0x1F == 0x1F else 1
  length_byte = data[tag_len]
  return tag_len + (1 + (length_byte & 0x7F) if length_byte & 0x80 else 1)


def _split_bpp(bpp: bytes) -> list[bytes]:
  """Split a BoundProfilePackage into APDU chunks per SGP.22 §5.7.6."""
  root_value = None
  for tag, value, start, end in iter_tlv(bpp, with_positions=True):
    if tag == TAG_BPP:

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Extract the confirmation code from the activation string: everything after the first '$$' in the QR code payload
  2. Prompt the user for the CC when the carrier provided one separately (SMS/email)
  3. Retry download passing the CC: download flow with cc='CODE' (via the CLI: append $$CODE in the QR argument if supported, or the API's cc parameter)

Example fix

# before
prepare_download(client, b64_signed2, b64_sig2, b64_cert)  # cc=None
# RuntimeError: Confirmation code required but not provided

# after — parse CC from the QR activation string
qr = 'LPA:1$rsp.truphone.com$QRF-TEST$$4321'
cc = qr.split('$$', 1)[1] if '$$' in qr else None
prepare_download(client, b64_signed2, b64_sig2, b64_cert, cc=cc)
Defensive patterns

Strategy: validation

Validate before calling

def extract_confirmation_code(qr: str) -> str | None:
  return qr.split('$$', 1)[1] if '$$' in qr else None

cc = extract_confirmation_code(qr_string)
# pass cc through to the download flow; server will still verify it

Try / catch

try:
  prepare_download(client, s2, sig2, cert, cc=cc)
except RuntimeError as e:
  if 'Confirmation code required' in str(e):
    cc = input('carrier confirmation code: ').strip()
    prepare_download(client, s2, sig2, cert, cc=cc)
  else:
    raise

Prevention

When it happens

Trigger: Downloading a profile whose QR/activation code includes a confirmation code (format ...$QRF-XXX$$CC123) but calling the download flow without extracting and passing the CC; carriers that always require a CC (e.g. some enterprise plans).

Common situations: QR string of the form LPA:1$rsp.example.com$ACTIVATION$$CODE where the code after $$ was stripped by the parser; interactive flows that didn't prompt; automation that ignores CC.

Related errors


AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15). Data as JSON: /api/errors/c5941d9e2af595c8. Report an issue: GitHub.