{"record":{"id":"71e34c5d1eda4f18","repo":"commaai/openpilot","slug":"profile-nickname-must-be-64-bytes-or-less","errorCode":null,"errorMessage":"Profile nickname must be 64 bytes or less","messagePattern":"Profile nickname must be 64 bytes or less","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"openpilot/common/esim/lpa.py","lineNumber":402,"sourceCode":"}\n\n\ndef decode_profiles(blob: bytes) -> list[dict]:\n  root = require_tag(blob, TAG_PROFILE_INFO_LIST, \"ProfileInfoList\")\n  list_ok = find_tag(root, TAG_OK)\n  if list_ok is None:\n    return []\n  return [decode_struct(value, PROFILE) for tag, value in iter_tlv(list_ok) if tag == 0xE3]\n\n\ndef list_profiles(client: AtClient) -> list[dict]:\n  return decode_profiles(es10x_command(client, TAG_PROFILE_INFO_LIST.to_bytes(2, \"big\") + b\"\\x00\"))\n\n\ndef set_profile_nickname(client: AtClient, iccid: str, nickname: str) -> None:\n  nickname_bytes = nickname.encode(\"utf-8\")\n  if len(nickname_bytes) > 64:\n    raise ValueError(\"Profile nickname must be 64 bytes or less\")\n  content = encode_tlv(TAG_ICCID, string_to_tbcd(iccid)) + encode_tlv(0x90, nickname_bytes)\n  response = es10x_command(client, encode_tlv(TAG_SET_NICKNAME, content))\n  code = require_tag(require_tag(response, TAG_SET_NICKNAME, \"SetNicknameResponse\"), TAG_STATUS, \"SetNickname status\")[0]\n  if code == 0x01:\n    raise LPAError(f\"profile {iccid} not found\")\n  if code != 0x00:\n    raise RuntimeError(f\"SetNickname failed with status 0x{code:02X}\")\n\n\n# --- ES9P HTTP ---\n\ndef es9p_request(smdp_address: str, endpoint: str, payload: dict, error_prefix: str = \"Request\", session: requests.Session | None = None) -> dict:\n  url = f\"https://{smdp_address}/gsma/rsp2/es9plus/{endpoint}\"\n  headers = {\"User-Agent\": \"gsma-rsp-lpad\", \"X-Admin-Protocol\": \"gsma/rsp/v2.3.0\", \"Content-Type\": \"application/json\"}\n  http = session or requests\n  resp = http.post(url, json=payload, headers=headers, timeout=HTTP_TIMEOUT, verify=GSMA_CI_BUNDLE)\n  resp.raise_for_status()\n  if not resp.content:","sourceCodeStart":384,"sourceCodeEnd":420,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/common/esim/lpa.py#L384-L420","documentation":"set_profile_nickname() validates the UTF-8 byte length of the nickname before encoding the ES10x SetNickname request. SGP.22 limits the nickname field to 64 bytes; exceeding it raises ValueError client-side without ever touching the modem.","triggerScenarios":"Calling set_profile_nickname(client, iccid, nickname) with nickname.encode('utf-8') longer than 64 bytes. Multibyte characters (emoji, CJK, accents) count per byte, so a 25-emoji nickname already exceeds 64 bytes even though it is 25 'characters'.","commonSituations":"Passing user-typed names/vehicle names from a UI without length checks; assuming the limit is 64 characters rather than 64 bytes; concatenating device identifiers into the nickname.","solutions":["Truncate by bytes, not characters, before calling: encode to UTF-8, slice to 64 bytes avoiding splitting a multibyte char","Strip/shorten the input at the UI layer with a byte-length counter","ASCII-ify or abbreviate long identifiers before using them as nicknames"],"exampleFix":"# before\nset_profile_nickname(client, iccid, '🚗 my awesome super long vehicle name with emoji 🚗')\n# ValueError: Profile nickname must be 64 bytes or less\n\n# after\ndef fit_nickname(name: str, limit: int = 64) -> str:\n  raw = name.encode('utf-8')\n  while len(raw) > limit:\n    name = name[:-1]\n    raw = name.encode('utf-8')\n  return name\n\nset_profile_nickname(client, iccid, fit_nickname(user_input))","handlingStrategy":"validation","validationCode":"def valid_nickname(name: str) -> bool:\n  return len(name.encode('utf-8')) <= 64\n\nassert valid_nickname(candidate), 'nickname exceeds 64 UTF-8 bytes'","typeGuard":"def is_valid_nickname(name: str) -> bool:\n  return 0 < len(name.encode('utf-8')) <= 64","tryCatchPattern":"try:\n  set_profile_nickname(client, iccid, name)\nexcept ValueError as e:\n  if '64 bytes' in str(e):\n    set_profile_nickname(client, iccid, name.encode('utf-8')[:64].decode('utf-8', errors='ignore'))\n  else:\n    raise","preventionTips":["Enforce a byte-length (not char-length) limit at the input UI","Prefer ASCII nicknames to avoid multibyte surprises","Truncate defensively before calling the API"],"tags":["esim","validation","unicode","sgp22","python"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}