commaai/openpilot · error · LPAError

EnableProfile failed: {PROFILE_ERROR_CODES.get(code, 'unknow

Error message

EnableProfile failed: {PROFILE_ERROR_CODES.get(code, 'unknown')} (0x{code:02X})

What it means

switch_profile() enables a profile via EnableProfile; after one retry following a CAT-busy reset, any status code besides PROFILE_OK or PROFILE_NOT_IN_DISABLED_STATE raises LPAError with the status name and hex code.

Source

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

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

  def _enable_profile(self, iccid: str) -> int:
    inner = encode_tlv(TAG_OK, encode_tlv(TAG_ICCID, string_to_tbcd(iccid)))
    inner += b'\x01\x01\x01'  # refreshFlag=1
    response = es10x_command(self._client, encode_tlv(TAG_ENABLE_PROFILE, inner))
    return require_tag(require_tag(response, TAG_ENABLE_PROFILE, "EnableProfileResponse"), TAG_STATUS, "EnableProfile status")[0]

  def switch_profile(self, iccid: str) -> None:
    with self._acquire_channel():
      code = self._enable_profile(iccid)
      if code == PROFILE_CAT_BUSY:  # stale eUICC transaction, reset and retry
        self._client._reset_modem()
        self._client.open_isdr()
        code = self._enable_profile(iccid)
      if code not in (PROFILE_OK, PROFILE_NOT_IN_DISABLED_STATE):
        raise LPAError(f"EnableProfile failed: {PROFILE_ERROR_CODES.get(code, 'unknown')} (0x{code:02X})")

  def is_euicc(self) -> bool:
    # +CCHO:<n> -> ISD-R applet present, eUICC. Any error -> non-eUICC.
    with self._acquire_lock():
      try:
        lines = self._client.query(f'AT+CCHO="{ISDR_AID}"')
      except RuntimeError:
        return False
      for line in lines:
        if line.startswith("+CCHO:") and (ch := line.split(":", 1)[1].strip()):
          try:
            self._client.query(f"AT+CCHC={ch}")
          except (RuntimeError, TimeoutError):
            pass
          self._client.channel = None
          return True
      return False

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Verify the ICCID exists via list_profiles() before switching
  2. Retry after a full modem reset / power cycle to clear stuck eUICC state
  3. Update AGNOS/modem firmware if the eUICC repeatedly returns unknown status codes
Defensive patterns

Strategy: retry

Validate before calling

assert any(p.iccid == iccid for p in lpa.list_profiles()), "unknown ICCID"

Try / catch

try:
    lpa.switch_profile(iccid)
except LPAError as e:
    if "EnableProfile failed" in str(e):
        lpa._client._reset_modem()
        lpa.switch_profile(iccid)

Prevention

When it happens

Trigger: switch_profile(iccid) where the ICCID is unknown, the target profile is already enabled (accepted) but the eUICC returns a different error, or a concurrent CAT/modem transaction keeps it busy past the built-in reset+retry.

Common situations: Switching to a profile that was deleted; eUICC in a stuck transaction state that survives one modem reset; unsupported profile state transitions on older eUICC firmware.

Related errors


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