{"record":{"id":"dd7b4ee57dde8572","repo":"commaai/openpilot","slug":"at-command-failed-line","errorCode":null,"errorMessage":"AT command failed: {line}","messagePattern":"AT command failed: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"openpilot/common/esim/lpa.py","lineNumber":175,"sourceCode":"    if DEBUG:\n      print(f\"SER >> {cmd}\", file=sys.stderr)\n    self._serial.write((cmd + \"\\r\").encode(\"ascii\"))\n\n  def _expect(self) -> list[str]:\n    lines: list[str] = []\n    while True:\n      raw = self._serial.readline()\n      if not raw:\n        raise TimeoutError(\"AT command timed out\")\n      line = raw.decode(errors=\"ignore\").strip()\n      if not line:\n        continue\n      if DEBUG:\n        print(f\"SER << {line}\", file=sys.stderr)\n      if line == \"OK\":\n        return lines\n      if line == \"ERROR\" or line.startswith(\"+CME ERROR\"):\n        raise RuntimeError(f\"AT command failed: {line}\")\n      lines.append(line)\n\n  def _ensure_serial(self, reconnect: bool = False) -> None:\n    if reconnect:\n      self.channel = None\n      try:\n        if self._serial:\n          self._serial.close()\n      except Exception:\n        pass\n      self._serial = None\n    if self._serial is None:\n      self._serial = Serial(self._device, baudrate=self._baud, timeout=self._timeout)\n\n  def query(self, cmd: str) -> list[str]:\n    self._ensure_serial()\n    try:\n      self._send(cmd)","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/common/esim/lpa.py#L157-L193","documentation":"While collecting the response to an AT command, _expect() received a line equal to 'ERROR' or starting with '+CME ERROR' — the modem explicitly rejected the command. The full offending line is embedded in the RuntimeError so the CMS/CME error code is visible.","triggerScenarios":"Malformed or unsupported AT commands (wrong parameter count for AT+CGLA, invalid channel/length), modem not registered/not ready for the requested operation, SIM PIN locked, or channel state lost so CGLA references a stale <channel>. '+CME ERROR: <n>' carries the specific mobile-equipment error code.","commonSituations":"The ISD-R logical channel closed underneath the client (modem reset) so subsequent AT+CGLA=<channel>,... fails; issuing AT commands before the modem finished booting; SIM locked or absent; modem firmware that doesn't support the requested command.","solutions":["Read the CME error number in the message and map it (e.g. 10 = SIM not inserted, 13 = SIM failure, 100 = unknown) to the actual condition","Reset the channel state and reopen: set client.channel = None and call open_isdr() again — the library already does this in send_apdu's retry loop","If SIM is PIN-locked or missing, resolve that at the modem level (check with AT+CPIN?) before eSIM operations","Reset the modem via lte.sh and retry once from a clean state if errors persist"],"exampleFix":"# before\nresp = client.query(f'AT+CGLA={client.channel},{len(hex_payload)},\"{hex_payload}\"')\n# RuntimeError: AT command failed: +CME ERROR: 100\n\n# after — drop the stale channel and reopen the ISD-R before retrying\nclient.channel = None\nclient.open_isdr()\nresp = client.query(f'AT+CGLA={client.channel},{len(hex_payload)},\"{hex_payload}\"')","handlingStrategy":"retry","validationCode":"status = client.query('AT+CPIN?')\nif any('SIM not ready' in l or 'ERROR' in l for l in status):\n  raise SystemExit('SIM/modem not ready; resolve before eSIM ops')","typeGuard":null,"tryCatchPattern":"try:\n  client.query('AT+CGLA=...')\nexcept RuntimeError as e:\n  if 'CME ERROR' in str(e) or str(e).endswith('failed: ERROR'):\n    client.channel = None\n    client.open_isdr()  # re-establish channel, then retry once\n    client.query('AT+CGLA=...')\n  else:\n    raise","preventionTips":["Treat any CME error as probable channel loss: clear channel and reopen ISD-R","Check AT+CPIN? / modem readiness before starting eSIM sessions","Log the CME code — recurring specific codes point to firmware/SIM issues, not transient ones"],"tags":["serial","modem","at-commands","esim","python"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}