commaai/openpilot · warning · ValueError
QR URL is too long
Error message
QR URL is too long
What it means
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'.
Source
Thrown at openpilot/common/qrcode.py:206
for vert in range(self.size):
y = self.size - 1 - vert if upward else vert
for x in (right, right - 1):
if not self.function[y][x]:
self.modules[y][x] = bool(next(bits, 0))
upward = not upward
right -= 2
def make_texture(data: str, inverted: bool = False) -> rl.Texture:
"""Render a URL as the RGBA QR texture used by the UI. The texture upload
copies the pixels, so the intermediate image/array don't need to outlive it."""
raw = data.encode()
for version in range(1, 21):
count_bits = 8 if version <= 9 else 16
if 4 + count_bits + len(raw) * 8 <= _capacity(version) * 8:
break
else:
raise ValueError("QR URL is too long")
modules = np.pad(_Qr(version, raw).modules, 0 if inverted else 4)
modules = np.repeat(np.repeat(modules, 10, axis=0), 10, axis=1)
gray = ((modules == inverted) * 255).astype(np.uint8)
img_array = np.dstack((gray, gray, gray, np.full_like(gray, 255)))
rl_image = rl.Image()
rl_image.data = rl.ffi.cast("void *", img_array.ctypes.data)
rl_image.width = img_array.shape[1]
rl_image.height = img_array.shape[0]
rl_image.mipmaps = 1
rl_image.format = rl.PixelFormat.PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
return rl.load_texture_from_image(rl_image)
View on GitHub (pinned to 516ec1e682)
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
Example fix
// before
make_texture(f"https://example.com/connect?token={huge_jwt}")
// after
make_texture(f"https://example.com/c/{short_code}") Defensive patterns
Strategy: validation
Validate before calling
MAX_QR_BYTES = 1273 # version 20, low EC, byte mode (approx)
def qr_encodable(data: str) -> bool:
return len(data.encode()) <= MAX_QR_BYTES Try / catch
try:
tex = make_texture(url)
except ValueError:
tex = make_texture(shorten(url)) Prevention
- Keep rendered URLs short — use short codes instead of embedded tokens
- Pre-check encoded length before rendering
When it happens
Trigger: 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.
Common situations: Passing a URL with huge query strings, embedded tokens, or accidentally passing a whole JSON payload instead of a URL.
AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15).
Data as JSON: /api/errors/b153b526a18ea9e6.
Report an issue: GitHub.