commaai/openpilot · error · RuntimeError

Missing +CGLA response

Error message

Missing +CGLA response

What it means

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.

Source

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

        time.sleep(OPEN_ISDR_RETRY_DELAY_S)
        if attempt == OPEN_ISDR_RESET_ATTEMPT:
          self._reset_modem()
    raise RuntimeError("Failed to open ISD-R after retries")

  def send_apdu(self, apdu: bytes) -> tuple[bytes, int, int]:
    for attempt in range(SEND_APDU_RETRIES):
      try:
        if not self.channel:
          self.open_isdr()
        hex_payload = apdu.hex().upper()
        for line in self.query(f'AT+CGLA={self.channel},{len(hex_payload)},"{hex_payload}"'):
          if line.startswith("+CGLA:"):
            parts = line.split(":", 1)[1].split(",", 1)
            if len(parts) == 2:
              data = bytes.fromhex(parts[1].strip().strip('"'))
              if len(data) >= 2:
                return data[:-2], data[-2], data[-1]
        raise RuntimeError("Missing +CGLA response")
      except (RuntimeError, ValueError):
        self.channel = None
        if attempt == SEND_APDU_RETRIES - 1:
          raise
    raise RuntimeError("send_apdu failed")


# --- TLV utilities ---

def iter_tlv(data: bytes, with_positions: bool = False) -> Generator:
  idx, length = 0, len(data)
  while idx < length:
    start_pos = idx
    tag = data[idx]
    idx += 1
    if tag & 0x1F == 0x1F:  # Multi-byte tag
      tag_value = tag
      while idx < length:

View on GitHub (pinned to 516ec1e682)

Solutions

  1. 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
  2. Reset the modem (lte.sh restart / _reset_modem) and retry the whole eSIM operation from the start
  3. Ensure exclusive access to the AT port (hold /dev/shm/modem.lock) so nothing else reads responses
  4. Update modem firmware if +CGLA omissions are reproducible with healthy channels

Example fix

# before
client.send_apdu(apdu)  # RuntimeError: Missing +CGLA response (after 3 retries)

# after — hard reset modem, rebuild client, retry once
client.close()
client._reset_modem()
client = AtClient()
client.send_apdu(apdu)
Defensive patterns

Strategy: retry

Try / catch

from openpilot.common.esim.lpa import AtClient

try:
  data, sw1, sw2 = client.send_apdu(apdu)
except RuntimeError as e:
  if 'Missing +CGLA response' in str(e):
    client.close()
    client._reset_modem()
    client = AtClient()
    data, sw1, sw2 = client.send_apdu(apdu)
  else:
    raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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