{"record":{"id":"de6bc36f708989d8","repo":"commaai/openpilot","slug":"invalid-boundprofilepackage","errorCode":null,"errorMessage":"Invalid BoundProfilePackage","messagePattern":"Invalid BoundProfilePackage","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"openpilot/common/esim/lpa.py","lineNumber":530,"sourceCode":"  return b64e(response)\n\n\ndef _parse_tlv_header_len(data: bytes) -> int:\n  tag_len = 2 if data[0] & 0x1F == 0x1F else 1\n  length_byte = data[tag_len]\n  return tag_len + (1 + (length_byte & 0x7F) if length_byte & 0x80 else 1)\n\n\ndef _split_bpp(bpp: bytes) -> list[bytes]:\n  \"\"\"Split a BoundProfilePackage into APDU chunks per SGP.22 §5.7.6.\"\"\"\n  root_value = None\n  for tag, value, start, end in iter_tlv(bpp, with_positions=True):\n    if tag == TAG_BPP:\n      root_value = value\n      val_start = start + _parse_tlv_header_len(bpp[start:end])\n      break\n  if root_value is None:\n    raise RuntimeError(\"Invalid BoundProfilePackage\")\n\n  chunks: list[bytes] = []\n  for tag, value, start, end in iter_tlv(root_value, with_positions=True):\n    if tag == TAG_BPP_COMMAND:\n      chunks.append(bpp[0 : val_start + end])\n    elif tag in (0xA0, 0xA2):\n      chunks.append(bpp[val_start + start : val_start + end])\n    elif tag in (0xA1, 0xA3):\n      hdr_len = _parse_tlv_header_len(root_value[start:end])\n      chunks.append(bpp[val_start + start : val_start + start + hdr_len])\n      for _, _, cs, ce in iter_tlv(value, with_positions=True):\n        chunks.append(value[cs:ce])\n  return chunks\n\n\ndef _parse_install_result(response: bytes) -> dict[str, Any] | None:\n  \"\"\"Parse a ProfileInstallResult from an APDU response, or None if not present.\"\"\"\n  root = find_tag(response, TAG_PROFILE_INSTALL_RESULT)","sourceCodeStart":512,"sourceCodeEnd":548,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/common/esim/lpa.py#L512-L548","documentation":"_split_bpp() chunks the BoundProfilePackage for installation per SGP.22 §5.7.6 by locating the root TAG_BPP (0xBF36) element via iter_tlv with positions. If the decoded bpp bytes contain no BF36 element, the structure is not recognized as a BPP and RuntimeError('Invalid BoundProfilePackage') is raised.","triggerScenarios":"load_bpp() is called with base64 that decodes to bytes lacking a BF36 root — wrong field passed (e.g. profileMetadata instead of boundProfilePackage), truncated BPP from a segmented server response, or a server-format mismatch (SGP.22 version differences in wrapping).","commonSituations":"Wiring bugs in custom download flows mixing up handleNotification response fields; carrier servers returning the BPP wrapped or encoded differently; base64 corruption (whitespace/newlines) truncating the payload.","solutions":["Verify you pass exactly the boundProfilePackage field from the ES9+ handleNotification response to load_bpp","Inspect the decoded bytes' first tags (hex dump) — a valid BPP starts with BF36; if it starts with another BF tag, the wrong field was used","Re-run the download from the QR; server-transient truncation yields a new, complete BPP (note: some already-consumed QRs cannot be reused)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import base64\nfrom openpilot.common.esim.lpa import find_tag, TAG_BPP\n\nraw = base64.b64decode(b64_bpp)\nif find_tag(raw, TAG_BPP) is None:\n  raise SystemExit('payload is not a BoundProfilePackage (no BF36); wrong field or corrupted BPP')","typeGuard":"def looks_like_bpp(b64: str) -> bool:\n  try:\n    return find_tag(base64.b64decode(b64), 0xBF36) is not None\n  except Exception:\n    return False","tryCatchPattern":null,"preventionTips":["Pass exactly the boundProfilePackage field of handleNotification to load_bpp","Hex-dump the BPP prefix when integration-testing new download flows","Strip whitespace/newlines from base64 before decoding"],"tags":["esim","bpp","tlv","parsing","sgp22","download","python"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}