{"record":{"id":"98b25f1d17bf75ad","repo":"commaai/openpilot","slug":"missing-cgla-response","errorCode":null,"errorMessage":"Missing +CGLA response","messagePattern":"Missing \\+CGLA response","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"openpilot/common/esim/lpa.py","lineNumber":252,"sourceCode":"        time.sleep(OPEN_ISDR_RETRY_DELAY_S)\n        if attempt == OPEN_ISDR_RESET_ATTEMPT:\n          self._reset_modem()\n    raise RuntimeError(\"Failed to open ISD-R after retries\")\n\n  def send_apdu(self, apdu: bytes) -> tuple[bytes, int, int]:\n    for attempt in range(SEND_APDU_RETRIES):\n      try:\n        if not self.channel:\n          self.open_isdr()\n        hex_payload = apdu.hex().upper()\n        for line in self.query(f'AT+CGLA={self.channel},{len(hex_payload)},\"{hex_payload}\"'):\n          if line.startswith(\"+CGLA:\"):\n            parts = line.split(\":\", 1)[1].split(\",\", 1)\n            if len(parts) == 2:\n              data = bytes.fromhex(parts[1].strip().strip('\"'))\n              if len(data) >= 2:\n                return data[:-2], data[-2], data[-1]\n        raise RuntimeError(\"Missing +CGLA response\")\n      except (RuntimeError, ValueError):\n        self.channel = None\n        if attempt == SEND_APDU_RETRIES - 1:\n          raise\n    raise RuntimeError(\"send_apdu failed\")\n\n\n# --- TLV utilities ---\n\ndef iter_tlv(data: bytes, with_positions: bool = False) -> Generator:\n  idx, length = 0, len(data)\n  while idx < length:\n    start_pos = idx\n    tag = data[idx]\n    idx += 1\n    if tag & 0x1F == 0x1F:  # Multi-byte tag\n      tag_value = tag\n      while idx < length:","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/common/esim/lpa.py#L234-L270","documentation":"send_apdu() sends an AT+CGLA command and scans the response lines for one starting with '+CGLA:'. If the modem replies only with 'Ok' (or unrelated lines) and no +CGLA payload line, the response cannot be parsed into (data, sw1, sw2) and RuntimeError('Missing +CGLA response') is raised.","triggerScenarios":"Modem acknowledges the command but omits the +CGLA data line — firmware quirk after channel state corruption, channel silently closed by modem, or a race where a previous response was consumed by another reader. Raised inside send_apdu's retry loop: channel is reset and the APDU retried up to SEND_APDU_RETRIES=3 times before surfacing.","commonSituations":"Modem dropped the logical channel between operations (modem internal reset); interleaved serial access by another process swallowing the +CGLA line; modem firmware that occasionally returns bare Ok for CGLA when the channel is invalid.","solutions":["Let the built-in retry run — it already clears self.channel and reopens the ISD-R; if the error still surfaces, the channel loss is persistent","Reset the modem (lte.sh restart / _reset_modem) and retry the whole eSIM operation from the start","Ensure exclusive access to the AT port (hold /dev/shm/modem.lock) so nothing else reads responses","Update modem firmware if +CGLA omissions are reproducible with healthy channels"],"exampleFix":"# before\nclient.send_apdu(apdu)  # RuntimeError: Missing +CGLA response (after 3 retries)\n\n# after — hard reset modem, rebuild client, retry once\nclient.close()\nclient._reset_modem()\nclient = AtClient()\nclient.send_apdu(apdu)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"from openpilot.common.esim.lpa import AtClient\n\ntry:\n  data, sw1, sw2 = client.send_apdu(apdu)\nexcept RuntimeError as e:\n  if 'Missing +CGLA response' in str(e):\n    client.close()\n    client._reset_modem()\n    client = AtClient()\n    data, sw1, sw2 = client.send_apdu(apdu)\n  else:\n    raise","preventionTips":["Rely on send_apdu's internal retry; treat surfacing of this error as 'channel persistently broken'","Serialize eSIM operations behind the modem lock to prevent interleaved reads","Keep modem firmware current — +CGLA omissions are firmware bugs"],"tags":["esim","modem","at-commands","retries","serial","python"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}