{"record":{"id":"5e196cad97fcbde9","repo":"commaai/openpilot","slug":"no-profile-at-index-ref-have-len-profiles","errorCode":null,"errorMessage":"no profile at index {ref} (have {len(profiles)})","messagePattern":"no profile at index (.+?) \\(have (.+?)\\)","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"openpilot/common/esim/esim.py","lineNumber":20,"sourceCode":"\nimport argparse\nimport sys\nimport time\nfrom openpilot.common.hardware import HARDWARE\nfrom openpilot.common.esim.base import LPABase, Profile\n\n\ndef sorted_profiles(lpa: LPABase) -> list[Profile]:\n  return sorted(lpa.list_profiles(), key=lambda p: p.iccid)\n\n\ndef resolve_iccid(lpa: LPABase, ref: str) -> str:\n  # ref is either a 1-based index into the sorted list, or a literal iccid\n  if ref.isdigit():\n    profiles = sorted_profiles(lpa)\n    idx = int(ref) - 1\n    if not 0 <= idx < len(profiles):\n      raise SystemExit(f'no profile at index {ref} (have {len(profiles)})')\n    return profiles[idx].iccid\n  return ref\n\n\ndef print_profiles(lpa: LPABase) -> None:\n  profiles = sorted_profiles(lpa)\n  print(f'\\n{len(profiles)} profile{\"s\" if len(profiles) != 1 else \"\"}:')\n  for i, p in enumerate(profiles, start=1):\n    print(f'{i}. {p.iccid} (nickname: {p.nickname or \"<none provided>\"}) (provider: {p.provider}) - {\"enabled\" if p.enabled else \"disabled\"}')\n\n\ndef execute_and_process_notifications(lpa: LPABase, operation) -> None:\n  try:\n    operation()\n  finally:\n    time.sleep(1)  # Need to wait for 1s after the operation is finished so the eUICC/modem can settle down.\n    try:\n      lpa.process_notifications()","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/common/esim/esim.py#L2-L38","documentation":"The esim CLI accepts a profile reference that is either a literal ICCID or a 1-based index into the alphabetically sorted (by ICCID) profile list. When the argument is all digits, it is treated as an index; if that index is out of range (idx < 0 or >= number of profiles), the script exits with SystemExit showing the list size.","triggerScenarios":"Running a command like `esim.py switch 3` or `esim.py delete 5 nickname` when the eUICC has fewer than that many profiles (e.g. 2 profiles and index 3, or index 0 / negative-looking values that parse via int()). Note a full ICCID is also all digits, so passing a real 19-20 digit ICCID that fits isdigit() can be misinterpreted as a huge index if it exceeds the profile count only in edge cases — in practice the index path triggers with short numeric args.","commonSituations":"User counts profiles from stale output (a profile was deleted since `list` was run); using 0-based indexing while the CLI expects 1-based; passing an ICCID string that is purely numeric and longer than the profile count is safe only if it matches len semantics — actually any digit string is treated as index, so passing a numeric ICCID always goes down the index branch.","solutions":["Run `esim.py list` first, note the current 1-based numbers and count, then reference a valid index within that count","Pass the literal ICCID instead of an index — but only non-purely-digit forms avoid the index branch; since ICCIDs are numeric, prefer re-running `list` and using a valid index","If the list is empty, download a profile before switching/deleting/renaming one","Treat this SystemExit message as authoritative: it tells you exactly how many profiles exist"],"exampleFix":"# before\npython -m openpilot.common.esim.esim switch 5   # only 2 profiles -> SystemExit\n\n# after\npython -m openpilot.common.esim.esim list\n# 2 profiles:\n# 1. 890000... (enabled)\n# 2. 890111... (disabled)\npython -m openpilot.common.esim.esim switch 2","handlingStrategy":"validation","validationCode":"from openpilot.common.esim.esim import sorted_profiles\n\nprofiles = sorted_profiles(lpa)\nidx = int(ref) if ref.isdigit() else None\nif idx is not None and not 1 <= idx <= len(profiles):\n  raise SystemExit(f'refresh profile list: only {len(profiles)} profiles, index {ref} invalid')","typeGuard":null,"tryCatchPattern":"try:\n  iccid = resolve_iccid(lpa, ref)\nexcept SystemExit as e:\n  print(f'invalid reference: {e}; run list to refresh')\n  raise","preventionTips":["Always run `list` immediately before switch/delete/nickname and copy the index fresh","Remember indices are 1-based and refer to the ICCID-sorted order","Prefer the exact ICCID over positional indices in scripts to avoid list-drift"],"tags":["esim","cli","argument-validation","user-input","python"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}