fbuild deploy -e <env> refuses to select a port when the board's currently running firmware advertises a USB identity that does not match the target environment — even though a healthy CDC port is present and an explicit -p deploys that same board successfully a second later.
On a Pico 2 W this makes switching between the rp2350 and rp2350w environments a one-way trip in each direction, because the firmware you just flashed determines whether you can flash the other one.
Observed
$ uv run fbuild port scan
/dev/ttyACM0 2E8A:000F Pico 2 ser=2DCB876B587EA334 if=MI_00
Arduino / Shared USB identity cdc=yes health=healthy
/dev/ttyACM2 303A:1001 USB JTAG/serial debug unit ser=8C:BF:EA:CF:87:B4
2 USB ports, 4 non-USB ports
$ fbuild .build/pio/rp2350w deploy -e rp2350w
deploy error: deploy failed: RP-series picotool deployment requires the selected
runtime USB serial so fbuild can bind the BOOTSEL operation to one board; use a
healthy USB CDC port selector or an explicit UF2=BOOTSEL-volume recovery path
port scan reports that exact port as cdc=yes health=healthy. The message asks for "a healthy USB CDC port selector", and one is present.
Same board, same moment, explicit port:
$ fbuild .build/pio/rp2350w deploy -e rp2350w -p /dev/ttyACM0 --skip-build
wrote /run/media/niteris/RP2350/NEW.UF2
deploy succeeded (full flash); FBUILD_DEPLOY_PORT=/dev/ttyACM0
It is the identity, and it is symmetric
The single physical board is a Pico 2 W. Its USB identity is set by whichever firmware is running:
| running firmware |
enumerates as |
deploy -e rp2350 |
deploy -e rp2350w |
rp2350 |
2E8A:000F "Pico 2" |
works |
refuses |
rp2350w |
2E8A:F00F "Pico 2W" |
refuses |
works |
I hit both directions. Controls, so this is not a general breakage: with the board on rp2350 firmware, bash autoresearch rp2350 --rpc-smoke deploys and passes; only the mismatched environment refuses. After recovering with -p, the identity flips to 2E8A:F00F and bash autoresearch rp2350w --rpc-smoke deploys and passes while rp2350 would then be the refused one.
Why this matters
The selector treats the current identity as evidence of what the board is, but for RP the identity is a property of the firmware image, not the silicon. A board that needs new firmware is precisely a board whose present identity should not be trusted — and BOOTSEL, which is where the deploy is headed anyway, is identity-free.
Unattended, this is a trap rather than an inconvenience: an agent or CI job that deploys rp2350 to a Pico 2 W has silently removed its own ability to deploy rp2350w to that board, with no warning at the time and an error afterwards that points at cabling and port health instead of at the cause.
Suggested direction
When the target is an RP-series environment and exactly one RP-family device is present, bind the BOOTSEL operation to that device rather than requiring the runtime identity to match the environment's expected VID:PID. The serial number (2DCB876B587EA334 here) is stable across both identities and already disambiguates a multi-board bench.
Failing that, the error should name the real cause — "the attached RP board is running firmware that enumerates as 2E8A:000F, which does not match environment rp2350w; pass -p <port> to deploy anyway" — so the remedy is visible without bisecting it.
Environment
- fbuild 2.5.23
- Linux 6.18.48, NixOS
- FastLED master
1843de8da7
- Board: Pico 2 W, serial
2DCB876B587EA334, direct motherboard USB
fbuild deploy -e <env>refuses to select a port when the board's currently running firmware advertises a USB identity that does not match the target environment — even though a healthy CDC port is present and an explicit-pdeploys that same board successfully a second later.On a Pico 2 W this makes switching between the
rp2350andrp2350wenvironments a one-way trip in each direction, because the firmware you just flashed determines whether you can flash the other one.Observed
port scanreports that exact port ascdc=yes health=healthy. The message asks for "a healthy USB CDC port selector", and one is present.Same board, same moment, explicit port:
It is the identity, and it is symmetric
The single physical board is a Pico 2 W. Its USB identity is set by whichever firmware is running:
deploy -e rp2350deploy -e rp2350wrp23502E8A:000F"Pico 2"rp2350w2E8A:F00F"Pico 2W"I hit both directions. Controls, so this is not a general breakage: with the board on
rp2350firmware,bash autoresearch rp2350 --rpc-smokedeploys and passes; only the mismatched environment refuses. After recovering with-p, the identity flips to2E8A:F00Fandbash autoresearch rp2350w --rpc-smokedeploys and passes whilerp2350would then be the refused one.Why this matters
The selector treats the current identity as evidence of what the board is, but for RP the identity is a property of the firmware image, not the silicon. A board that needs new firmware is precisely a board whose present identity should not be trusted — and BOOTSEL, which is where the deploy is headed anyway, is identity-free.
Unattended, this is a trap rather than an inconvenience: an agent or CI job that deploys
rp2350to a Pico 2 W has silently removed its own ability to deployrp2350wto that board, with no warning at the time and an error afterwards that points at cabling and port health instead of at the cause.Suggested direction
When the target is an RP-series environment and exactly one RP-family device is present, bind the BOOTSEL operation to that device rather than requiring the runtime identity to match the environment's expected VID:PID. The serial number (
2DCB876B587EA334here) is stable across both identities and already disambiguates a multi-board bench.Failing that, the error should name the real cause — "the attached RP board is running firmware that enumerates as 2E8A:000F, which does not match environment rp2350w; pass
-p <port>to deploy anyway" — so the remedy is visible without bisecting it.Environment
1843de8da72DCB876B587EA334, direct motherboard USB