{"record":{"id":"b153b526a18ea9e6","repo":"commaai/openpilot","slug":"qr-url-is-too-long","errorCode":null,"errorMessage":"QR URL is too long","messagePattern":"QR URL is too long","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"openpilot/common/qrcode.py","lineNumber":206,"sourceCode":"      for vert in range(self.size):\n        y = self.size - 1 - vert if upward else vert\n        for x in (right, right - 1):\n          if not self.function[y][x]:\n            self.modules[y][x] = bool(next(bits, 0))\n      upward = not upward\n      right -= 2\n\n\ndef make_texture(data: str, inverted: bool = False) -> rl.Texture:\n  \"\"\"Render a URL as the RGBA QR texture used by the UI. The texture upload\n  copies the pixels, so the intermediate image/array don't need to outlive it.\"\"\"\n  raw = data.encode()\n  for version in range(1, 21):\n    count_bits = 8 if version <= 9 else 16\n    if 4 + count_bits + len(raw) * 8 <= _capacity(version) * 8:\n      break\n  else:\n    raise ValueError(\"QR URL is too long\")\n  modules = np.pad(_Qr(version, raw).modules, 0 if inverted else 4)\n  modules = np.repeat(np.repeat(modules, 10, axis=0), 10, axis=1)\n  gray = ((modules == inverted) * 255).astype(np.uint8)\n  img_array = np.dstack((gray, gray, gray, np.full_like(gray, 255)))\n\n  rl_image = rl.Image()\n  rl_image.data = rl.ffi.cast(\"void *\", img_array.ctypes.data)\n  rl_image.width = img_array.shape[1]\n  rl_image.height = img_array.shape[0]\n  rl_image.mipmaps = 1\n  rl_image.format = rl.PixelFormat.PIXELFORMAT_UNCOMPRESSED_R8G8B8A8\n  return rl.load_texture_from_image(rl_image)\n","sourceCodeStart":188,"sourceCodeEnd":219,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/common/qrcode.py#L188-L219","documentation":"make_texture() searches QR versions 1..20 for one whose capacity fits the URL (with a 4-bit or 16-bit length prefix). If even version 20 (177x177 modules) cannot hold len(data), it raises ValueError 'QR URL is too long'.","triggerScenarios":"Calling make_texture(url) where the encoded URL exceeds the byte capacity of QR version 20 at the chosen error-correction level — roughly 1-2 KB depending on level.","commonSituations":"Passing a URL with huge query strings, embedded tokens, or accidentally passing a whole JSON payload instead of a URL.","solutions":["Shorten the URL (use a redirect/short-link service or trim query parameters)","Verify you are passing the URL string, not an encoded payload object","If long data is required, split it across multiple QR renders or use a data channel other than QR"],"exampleFix":"// before\nmake_texture(f\"https://example.com/connect?token={huge_jwt}\")\n\n// after\nmake_texture(f\"https://example.com/c/{short_code}\")","handlingStrategy":"validation","validationCode":"MAX_QR_BYTES = 1273  # version 20, low EC, byte mode (approx)\n\ndef qr_encodable(data: str) -> bool:\n    return len(data.encode()) <= MAX_QR_BYTES","typeGuard":null,"tryCatchPattern":"try:\n    tex = make_texture(url)\nexcept ValueError:\n    tex = make_texture(shorten(url))","preventionTips":["Keep rendered URLs short — use short codes instead of embedded tokens","Pre-check encoded length before rendering"],"tags":["qrcode","encoding","ui"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}