show actionable fix when USB device access is denied on Linux#215
Open
itsdestin wants to merge 1 commit into
Open
show actionable fix when USB device access is denied on Linux#215itsdestin wants to merge 1 commit into
itsdestin wants to merge 1 commit into
Conversation
On Linux, /dev/bus/usb device nodes are typically root-owned without
group write access, so USBDevice.open() throws SecurityError ('Access
denied.') and flashing fails instantly. This was previously reported as
generic LOST_CONNECTION with a hint blaming qcserial, which misdirects
users who already unbound it.
Detect the SecurityError (preserved as the error cause by qdl.js) and
show a dedicated error screen with a copyable one-time udev rule fix.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On Linux,
/dev/bus/usbdevice nodes are typically root-owned with mode0664(no write access for regular users — stock behavior on Arch and others). Chrome can enumerate the device, so it appears in the WebUSB picker and every wizard step passes, butUSBDevice.open()then throwsSecurityError: Access denied.and flashing fails instantly.Today that surfaces as a generic LOST_CONNECTION ("Lost connection… Did you forget to unbind the device from qcserial?") — which misdirects users who did unbind. We lost a while to cable/port/USB-speed theories before tracing it to permissions. Reports like #192 (
error 4, console showsConnection error {}, no resolution) suggest this conflation is generating undiagnosable bug reports.Verified on CachyOS (Arch-based), Chrome 148, comma 3X: the failure was instant and identical across cables, ports, and USB 2/3 enumeration;
sudo chmod 666on the device node, with no other change, made the very next attempt flash to completion.Change
manager.js: newErrorCode.ACCESS_DENIED, detected in#connect()by walking the errorcausechain forSecurityError(qdl.js preserves the original DOMException ascause). All other connect failures still map toLOST_CONNECTION.Flash.jsx: dedicated error screen forACCESS_DENIED. On Linux it shows a copyable one-time fix — a udev rule usingTAG+="uaccess"(the approach recommended by Chromium developers), covering both05c6:9008(comma 3/3X) and3801:9008(comma four). On non-Linux platforms (e.g. Windows, whereSecurityErrorusually means another program holds the device) it shows a generic message.manager.test.js: unit tests for the detection (directSecurityError, wrapped ascause, negative cases).Precedent: commaai/openpilot#34674 added the equivalent udev rule for panda DFU mode.
An alternative/complementary approach would be adding the udev rule to the Linux "Unbind" wizard step so the error never happens — happy to extend this PR that way if preferred.
Verification
bun run buildpassesvitest run src/utils/manager.test.js— 3/3 passstream.test.jspasses;manifest.test.jsfails identically on unmodified master (live manifest has 32 images vs expected 33 — unrelated)🤖 Generated with Claude Code