device descriptor read/64, error -71: Raspberry Pi USB fix
When a USB device keeps dropping off a Raspberry Pi, the kernel log fills with device descriptor read/64, error -71 and the device never finishes enumerating. This is not a driver problem, a filesystem problem, or a sign that the board is dying: the USB bus itself is failing the very first handshake with the device, and on a Pi the root cause is almost always electrical.
I have chased this exact log line on two different rigs: a Pi 4 kiosk whose 4G modem vanished every few hours, and a Pi 3 that refused to talk to a printer controller board hanging off a powered hub. Same error, different physics. The log shows a storm — reset, descriptor read, fail, reset again — and most forum advice jumps straight to kernel parameters. That is backwards. The fix order that actually works is: power, cable, hub, then autosuspend. Kernel tweaks come last, and usually are not needed at all.
TL;DR
- -71 is -EPROTO (protocol error). During enumeration the kernel sends a
GET_DESCRIPTORcontrol transfer, and the device answers with data that fails validation, or the transfer dies mid-flight. The kernel logs the failure and retries with port resets. - The repeating lines are normal kernel behavior, not a crash. Each plug event ends with
device not accepting address N, error -71andunable to enumerate USB device. The port stays dead until you unplug and replug. - On a Pi, power is the first suspect. Run
vcgencmd get_throttled: bit 0 means undervoltage right now, bit 16 means it has happened since boot. An adequate supply or a powered hub resolves most cases. - If it only fails after idle, suspect USB autosuspend. Disable it with
usbcore.autosuspend=-1on the kernel command line — a two-line change, no driver rebuild. - Isolate before you configure. Try a known-good device on the same port, then the failing device on another machine. Ten minutes of swapping hardware beats a day of kernel options.
💡 The same workflow applies to other kernel-level device failures on the Pi. We have already torn down mmc0: error -110 whilst initialising SD card (an SD-card controller timeout — same -110 ETIMEDOUT family you will see when a USB device does not answer at all) and Klipper "MCU 'mcu' shutdown: ADC out of range" (a controller board that talks to the Pi over USB). Capture the exact log line first, then fix the physical layer.
What the kernel is actually doing when it logs error -71
When you plug a device in, the hub driver (drivers/usb/core/hub.c, function hub_port_init) resets the port and issues a GET_DESCRIPTOR control transfer to learn the device's maximum packet size (bMaxPacketSize0). The kernel source is explicit about the validation: only 8, 16, 32, 64, and the special case 9 are accepted. If the device answers with anything else — or the transfer errors — the kernel sets rc = -EPROTO and, after the retries are exhausted, logs device descriptor read/64, error %d with that error code.
That gives you the reading key for the whole log. -71 means the device answered, but its answer made no sense. -110 means the opposite: no answer at all within the timeout. The distinction matters for triage. A device that replies with garbage is usually fighting the electrical layer — power delivery or signal integrity. A device that never replies is dead, unpowered, or stuck in a bad state.
| dmesg error | errno | What it means during enumeration |
|---|---|---|
| -71 | EPROTO (71) — Protocol error | Device responded, but the descriptor failed validation or the transfer aborted |
| -110 | ETIMEDOUT (110) — Connection timed out | No response at all within the timeout |
| -32 | EPIPE (32) — Broken pipe | Transfer aborted mid-stream, typically after repeated resets |
The numeric values come straight from include/uapi/asm-generic/errno.h in the kernel tree (EPROTO 71, ETIMEDOUT 110, EPIPE 32). Read the dmesg sequence as a story: reset, descriptor read fails, reset again, fails again, hub driver gives up on this plug event. The kernel logs every attempt, which is why one physical plug produces a wall of identical lines.
⚠️ It is not a runaway loop and it is not corrupting anything by itself. But if the flapping device is a disk, take it out of service until it is stable: a storage device that drops mid-write can corrupt the filesystem, which then produces a second, unrelated set of errors that will send you down the wrong path entirely.
Step 1: capture the exact pattern before changing anything
Reproduce the failure with the kernel log in front of you. Plug the device in while watching, and note the port address in the messages (usb 1-1.2, usb 2-1 — bus-port notation). That address tells you which physical port and hub level is failing, which is the first clue for the isolation tests later.
# Terminal 1: watch kernel messages live while you plug the device in.
sudo journalctl -k -f
# No journald on the system? Use the legacy ring buffer instead.
sudo dmesg -w
A clean enumeration ends with the device descriptors being read and a driver binding: New USB device found, idVendor=xxxx, idProduct=yyyy, then the USB-storage or serial lines, then the /dev node appearing. A failing enumeration never reaches that point — the log shows descriptor read errors and ends each attempt with unable to enumerate USB device. Confirm from a second terminal that the device is absent from the topology:
# Terminal 2: is the device present in the USB tree at all?
lsusb
lsusb -t # tree view: shows the hub/port the device should sit under
Save this baseline. After every fix below, replug and compare — you are looking for the descriptor error lines to stop appearing and for the device to stay in lsusb -t.
Step 2: power audit first — the Raspberry Pi edition
The Pi's USB ports are fed from the same 5 V rail as the SoC. When a high-current device — a 4G modem, a USB SSD, a camera, several bus-powered peripherals at once — draws more than the supply can hold, the rail sags and enumeration fails exactly this way. The classic symptom is a device that works for a moment and then drops, or fails at boot when everything powers up at the same instant.
Ask the firmware whether the rail has been sagging. vcgencmd get_throttled returns a bitmask of power and thermal state, documented in the official Raspberry Pi documentation:
# Undervoltage since boot? Bit 16 set = yes.
vcgencmd get_throttled
# throttled=0x0 -> clean: no power or thermal event since boot
# throttled=0x50000 -> undervoltage HAS occurred since boot (bit 16)
| Bit | Hex value | Meaning |
|---|---|---|
| 0 | 0x1 | Undervoltage detected right now |
| 1 | 0x2 | Arm frequency capped right now |
| 2 | 0x4 | Currently throttled |
| 16 | 0x10000 | Undervoltage has occurred since boot |
| 18 | 0x40000 | Throttling has occurred since boot |
Bits 16 and above latch until a full power cycle, so they are your history. On the desktop you will also see a lightning bolt icon in the top-right corner of the HDMI output while undervoltage is active. If the machine is headless, the firmware messages Under-voltage detected! into the kernel log.
Fixes, in order of likelihood:
- Use a supply that matches the board. The official Pi 4 supply is 5.1 V / 3 A USB-C; earlier boards use 5.1 V / 2.5 A micro-USB. A phone charger marked "5 V / 2 A" is not enough once peripherals are attached, and many cheap chargers sag well below their label under load.
- Suspect the cable before the supply. USB-C cables vary enormously in conductor gauge. A thin or damaged cable can drop enough voltage under load to trip the undervoltage threshold even when the supply itself is fine. Swap in the cable that shipped with the board.
- Stop feeding hungry devices through the Pi's ports. The durable fix for a modem, SSD, or radio is a powered hub with its own supply: the Pi then only carries signaling to the hub, and the hub carries the current.
Step 3: isolate device, cable, port, hub
Do the swaps now, before touching any configuration. Each test takes one minute and each one eliminates a whole class of causes:
- Known-good device on the same port. A USB stick that enumerates cleanly proves the port, the cable, and the Pi's power path are fine — the fault is the device.
- The failing device on another machine. If it enumerates cleanly on a laptop or desktop, the device is fine and the problem is on the Pi side: port connector, supply, or rail.
- Bypass the hub. Unpowered hubs in a chain are the single most common cause of -71 storms. Plug the device directly into a Pi port, or into one powered hub, not three daisy-chained bus-powered ones.
- Shorten the path. Long passive USB extension cables and marginal adapters degrade signal integrity. Use the shortest cable that physically fits.
- On a Pi 4, try a USB 2.0 port. Some legacy devices enumerate more reliably at high speed than at SuperSpeed. The USB 2.0 ports on the Pi 4 are the two black ones; the blue ports are USB 3.0.
If the device works on another machine but fails on every Pi port with a known-good supply, the remaining physical suspects are the port connector itself (dirt, a damaged socket) and the Pi's power input path. A powered hub sidesteps both: it re-generates clean power and a clean signal close to the device.
Step 4: disable USB autosuspend when idle is the trigger
The second real cause is software, and it has a signature: the device is fine at boot, vanishes after minutes of idle, and the -71 storm starts when something tries to use it again. Linux autosuspends idle USB devices by default — the usbcore.autosuspend parameter defaults to 2 seconds — and some devices (modems, audio interfaces, certain storage bridges) never resume cleanly. The wake attempt produces exactly this enumeration error loop.
# Confirm autosuspend is on: prints seconds of idle before suspend.
# 2 = the kernel default. -1 = disabled.
cat /sys/module/usbcore/parameters/autosuspend
To disable it globally, append usbcore.autosuspend=-1 to the kernel command line. On Raspberry Pi OS Bookworm and later the firmware files live under /boot/firmware; Bullseye and earlier used /boot directly. The file must remain a single line, so the safe edit is an append:
# Bookworm+: /boot/firmware/cmdline.txt
# Bullseye-: /boot/cmdline.txt
sudo cp /boot/firmware/cmdline.txt /boot/firmware/cmdline.txt.bak
sudo sed -i 's/$/ usbcore.autosuspend=-1/' /boot/firmware/cmdline.txt
sudo reboot
# After reboot, confirm the parameter took:
cat /sys/module/usbcore/parameters/autosuspend # prints -1
⚠️ If you edit cmdline.txt by hand instead, append the parameter with a single leading space and do not add a newline — a wrapped command line breaks the boot.
Prefer a surgical fix? Pin runtime power management to on for just the failing device with a udev rule. Grab its idVendor and idProduct from lsusb, then save this file (it is configuration, not a script — nothing executes it):
# /etc/udev/rules.d/50-usb-no-autosuspend.rules
# Replace 1234 and 5678 with the idVendor:idProduct from `lsusb`.
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="1234", ATTR{idProduct}=="5678", ATTR{power/control}="on"
Reload the udev rules, replug the device, and confirm the attribute stuck:
sudo udevadm control --reload
# Replug the device, then verify runtime PM is forced on.
# The sysfs path comes from `lsusb -t`: Bus 01, Port 2 -> 1-2.
cat /sys/bus/usb/devices/1-2/power/control # prints "on" when the rule applied
The global command-line switch is the right call for a headless Pi that runs one job — the extra power draw of keeping USB awake is negligible. The udev rule is the right call when other devices on the bus must keep autosuspending.
Step 5: verify with a clean enumeration
After each change, replug the device and watch the log the same way you did in Step 1. The fix is verified when the descriptor error lines stop appearing, the device stays in lsusb -t, and it survives the exact condition that used to kill it — boot, load, or the idle cycle.
# Replug the device, then check the recent kernel log. No descriptor
# errors = clean enumeration.
sudo journalctl -k --since "5 minutes ago" | grep -iE "usb|descriptor" | tail -40
# If the device is storage, prove it end-to-end.
# Use the real device node from `lsblk`; never guess.
sudo dd if=/dev/sda of=/dev/null bs=1M count=256 status=progress
If the storm still appears with a known-good device, a known-good supply, and autosuspend off, the remaining suspects are the cable, the connector, and the device itself — replace them in that order. One last software note: if the failure happens at boot for a device that was already powered before the Pi started, unplug and replug it once after boot. The kernel source itself notes that some devices time out when they are powered on while already connected and need a second reset. That one replug is the second reset.
Related hardware and ops posts
Kernel-level device errors all look alike until you capture the exact line, and they all share the same discipline: read the log, isolate the layer, fix the cheapest cause first. The rest of the series:
- mmc0: error -110 whilst initialising SD card — the SD-card controller timing out, the storage-side cousin of the USB timeout.
- Klipper "MCU 'mcu' shutdown: ADC out of range" — a controller board error that usually turns out to be wiring and power, exactly like this one.
Rule of thumb: when the log says error -71, think electrical before you think software. Power, cable, hub, then autosuspend — in that order. The kernel is telling you the device answered badly or not at all, and on a Raspberry Pi the 5 V rail is the usual suspect.