commaai/openpilot · error · LPAProfileNotFoundError

profile not found: {iccid}

Error message

profile not found: {iccid}

What it means

Lpa.delete_profile(iccid) looks up the requested ICCID in list_profiles(); if no profile matches, it raises LPAProfileNotFoundError with the requested ICCID. It indicates the eUICC has no such profile (or the ICCID string does not exactly match).

Source

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

          enabled=p.get("profileState") == "enabled",
          provider=p.get("serviceProviderName") or "",
        )
        for p in list_profiles(self._client)
      ]

  def get_active_profile(self) -> Profile | None:
    return None

  def process_notifications(self) -> None:
    if not system_time_valid():
      raise RuntimeError("System time is not set; TLS certificate validation requires a valid clock")
    with self._acquire_channel():
      process_notifications(self._client)

  def delete_profile(self, iccid: str) -> None:
    profile = next((p for p in self.list_profiles() if p.iccid == iccid), None)
    if profile is None:
      raise LPAProfileNotFoundError(f"profile not found: {iccid}")
    if profile.is_comma:
      raise LPAError("refusing to delete a comma profile")
    with self._acquire_channel():
      request = encode_tlv(TAG_DELETE_PROFILE, encode_tlv(TAG_ICCID, string_to_tbcd(iccid)))
      response = es10x_command(self._client, request)
      code = require_tag(require_tag(response, TAG_DELETE_PROFILE, "DeleteProfileResponse"), TAG_STATUS, "DeleteProfile status")[0]
    if code != PROFILE_OK:
      raise LPAError(f"DeleteProfile failed: {PROFILE_ERROR_CODES.get(code, 'unknown')} (0x{code:02X})")

  def download_profile(self, qr: str, nickname: str | None = None) -> None:
    with self._acquire_channel():
      iccid = download_profile(self._client, qr)
      if nickname and iccid:
        set_profile_nickname(self._client, iccid, nickname)

  def nickname_profile(self, iccid: str, nickname: str) -> None:
    with self._acquire_channel():
      set_profile_nickname(self._client, iccid, nickname)

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Call list_profiles() immediately before deleting and pass the exact iccid from that result
  2. Normalize the ICCID (strip spaces/dashes) before comparing
  3. Treat LPAProfileNotFoundError as a benign idempotent delete success where appropriate

Example fix

// before
delete_profile("89 00 12 34 ...")

// after
profiles = {p.iccid: p for p in lpa.list_profiles()}
if iccid in profiles:
    lpa.delete_profile(iccid)
Defensive patterns

Strategy: validation

Validate before calling

iccid = iccid.replace(" ", "").replace("-", "")
exists = any(p.iccid == iccid for p in lpa.list_profiles())

Try / catch

try:
    lpa.delete_profile(iccid)
except LPAProfileNotFoundError:
    pass  # already gone — treat as success

Prevention

When it happens

Trigger: Calling delete_profile with an ICCID from a stale cache, a typo, or one whose profile was already deleted; ICCID formatting differences (spaces/check digit) also fail the exact string comparison.

Common situations: UI lets the user act on a cached profile list that changed; ICCID copied with separators; profile removed on another device.

Related errors


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