{"record":{"id":"1f9abc8e41bc7e9a","repo":"commaai/openpilot","slug":"refusing-to-delete-a-comma-profile","errorCode":null,"errorMessage":"refusing to delete a comma profile","messagePattern":"refusing to delete a comma profile","errorType":"exception","errorClass":"LPAError","httpStatus":null,"severity":"error","filePath":"openpilot/common/esim/lpa.py","lineNumber":742,"sourceCode":"        )\n        for p in list_profiles(self._client)\n      ]\n\n  def get_active_profile(self) -> Profile | None:\n    return None\n\n  def process_notifications(self) -> None:\n    if not system_time_valid():\n      raise RuntimeError(\"System time is not set; TLS certificate validation requires a valid clock\")\n    with self._acquire_channel():\n      process_notifications(self._client)\n\n  def delete_profile(self, iccid: str) -> None:\n    profile = next((p for p in self.list_profiles() if p.iccid == iccid), None)\n    if profile is None:\n      raise LPAProfileNotFoundError(f\"profile not found: {iccid}\")\n    if profile.is_comma:\n      raise LPAError(\"refusing to delete a comma profile\")\n    with self._acquire_channel():\n      request = encode_tlv(TAG_DELETE_PROFILE, encode_tlv(TAG_ICCID, string_to_tbcd(iccid)))\n      response = es10x_command(self._client, request)\n      code = require_tag(require_tag(response, TAG_DELETE_PROFILE, \"DeleteProfileResponse\"), TAG_STATUS, \"DeleteProfile status\")[0]\n    if code != PROFILE_OK:\n      raise LPAError(f\"DeleteProfile failed: {PROFILE_ERROR_CODES.get(code, 'unknown')} (0x{code:02X})\")\n\n  def download_profile(self, qr: str, nickname: str | None = None) -> None:\n    with self._acquire_channel():\n      iccid = download_profile(self._client, qr)\n      if nickname and iccid:\n        set_profile_nickname(self._client, iccid, nickname)\n\n  def nickname_profile(self, iccid: str, nickname: str) -> None:\n    with self._acquire_channel():\n      set_profile_nickname(self._client, iccid, nickname)\n\n  def _enable_profile(self, iccid: str) -> int:","sourceCodeStart":724,"sourceCodeEnd":760,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/common/esim/lpa.py#L724-L760","documentation":"delete_profile refuses with LPAError when the target profile has is_comma set — a safety interlock preventing deletion of the device's own comma-managed operational profile. Deleting it could break the device's cellular connectivity managed by comma.","triggerScenarios":"Calling delete_profile on the profile whose metadata marks it as the comma provisioning profile (profile.is_comma True).","commonSituations":"User or tool attempts to wipe all profiles including the device's own; automated cleanup loops that iterate every profile from list_profiles().","solutions":["Skip is_comma profiles when iterating list_profiles for deletion","Delete only user-installed profiles identified by ICCID","If intentional decommissioning is needed, use comma's official deprovisioning path rather than delete_profile"],"exampleFix":"// before\nfor p in lpa.list_profiles():\n    lpa.delete_profile(p.iccid)\n\n// after\nfor p in lpa.list_profiles():\n    if not p.is_comma:\n        lpa.delete_profile(p.iccid)","handlingStrategy":"type-guard","validationCode":"target = next((p for p in lpa.list_profiles() if p.iccid == iccid), None)\nif target is None or target.is_comma:\n    skip_delete(iccid)","typeGuard":"def is_deletable(profile) -> bool:\n    return not profile.is_comma","tryCatchPattern":"try:\n    lpa.delete_profile(iccid)\nexcept LPAError as e:\n    if \"comma profile\" in str(e):\n        log.warning(\"refusing to delete comma profile\")\n    else:\n        raise","preventionTips":["Filter is_comma profiles out of any bulk-delete loop","Surface the interlock in UI so users understand the restriction"],"tags":["esim","lpa","safety","euicc"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}