You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Cannot Save code.py Edits on Adafruit Qualia ESP32-S3 for TTL RGB-666 Displays #460
Connect to board (ESP32-S3 Qualia) with web workflow
Open code.py
Edit code.py
Select "Save + Run". Board appears to reload and restart code.py
Connect to another board with web workflow
Open code.py on second board
Dialog box appears asking if I want to save edits to the previous code.py file. I select 'no'.
Connect again to first board (ESP32-S3 Qualia)
Open code.py. Can clearly see that previous edits were not saved.
Tried making edits again then just saving code.py
Connect again to another board with web workflow
Open code.py on second board (again). Again get dialog box asking if I want to save edits to previous code.py file. I select 'no'.
Connect for third time to first board (ESP32-S3 Qualia)
Open code.py. Can clearly see that previous edits were not saved (again).
Description
Cannot seem to save edits to code.py on ESP32-S3 Qualia.
I also notice that after trying to save code.py on ESP32-S3 Qualia that the web editor screen appears to be regularly reloading every second or two. This reload cycle does not stop until I connect to another board via wifi.
Thank you @makermelissa for resolving this issue. I tested it and I can now edit and reload my code.py on my Qualia ESP32-S3. I do see a warning popup during the save and reload operation which indicates that the browser was trying and failing to write code.py, but it does succeed (the popup appears and disappears quickly). Does not appear to affect performance, though. Thank you again!
Hmmm. Upon further inspection it appears that code.py is in fact not being written when I try to save or save+run. The error popup I receive is attached, which I get when I try to just save code.py.
I just noticed you are using Firefox. When this was originally written, it only worked on Chrome/Edge, so perhaps maybe it sort of works on Firefox now.
I'll have to give it a try with FF soon. Come to think of it, I think Web Workflow should be fine. It would be the BLE/USB that would likely have trouble due to WebBluetooth and WebSerial support..
I was able to reproduce the issue in both chrome and firefox. Essentially, the file system was mounted read-only, but the error messaging wasn't very good to indicate this.
I generally use web workflow with Firefox (current version is 140.9.0esr) on MacOS Sequoia 15.7.7.
I just double-checked the behaviour. Project is connected to power-only USB (no USB mount of CIRCUITPY). When I try to edit code.py via web workflow and save+run the changes I get your pop-up message. Sorry for the trouble.
I have multiple Adafruit wifi-enabled boards running CircuitPython on my home network which I regularly use web workflow to connect to an edit/debug. I had not tried using web workflow recently where I edited code.py and tried to save+run. Just tried that on a QtPy ESP32-S3 (8Mb flash no psram) based project (using the Firefox browser noted above) and see the same behaviour (pop-up noting board filesystem lock when I am connected to power-only USB. I don't recall having CIRCUITPY file system write issues in the past with any of my CIRCUITPY projects.
@jmangum thanks for the careful reproduction — the cross-browser
testing (Firefox / Safari / Chrome) and the second device (QtPy
ESP32-S3) were exactly what I needed to convince myself this isn't
a misconfiguration on your end.
Here's where I've landed:
1. The dialog from #498 is wrong for your case. It tells you a
host has CIRCUITPY mounted over USB, but in your setup nothing is
mounting it — you're on power-only USB. After walking through the
CircuitPython firmware, the actual cause is that the board's MP_BLOCKDEV_FLAG_LOCKED flag is held whenever USB Mass Storage is enabled on the board (which is the default on most boards),
regardless of whether a host is actively using the drive. The
dialog conflated those two cases.
2. Short-term fix — better messaging. I just opened #506 to
rewrite the read-only / save-failure dialogs so they don't assert
host involvement, and to add a heads-up about the dual-workflow
tradeoff (Mu over USB vs. web workflow). That should land soon and
will at least stop the dialog from sending you on a goose chase.
3. The real fix is on the firmware side, and it isn't quick.
Your "I want both Mu and web workflow on the same project" workflow
is legitimate, and boot.py disabling USB MSC unconditionally is a
blunt instrument. The cleanest path forward is firmware-side: the
board should release the MSC lock when no host has actually used it
in a while, or expose a cooperative way for web workflow to acquire
write access. I'm going to open a separate issue/discussion on adafruit/circuitpython
to track that, and I'll link it here so you can follow along.
In the meantime, two workarounds that preserve dual-mode editing:
Button-gated boot.py — the most popular pattern. Hold a
button at boot to disable USB MSC; otherwise leave it on. Lets
you choose Mu mode (no button) or web-workflow mode (hold button)
per power cycle. Example sketch:
# boot.pyimportboard, digitalio, storagebtn=digitalio.DigitalInOut(board.BUTTON) # or whatever pinbtn.pull=digitalio.Pull.UPifnotbtn.value: # button held at bootstorage.disable_usb_drive() # web-workflow mode# otherwise, default behavior: CIRCUITPY appears as MSC,# and Mu/Thonny/your-OS can edit code.py over USB
Power-vs-data USB switching — if your project always sits on
a power adapter once deployed, a true USB power-only cable (data
lines physically disconnected) doesn't expose CIRCUITPY to any
host. Some "charging only" cables do this; many don't (most modern
ones carry data). A USB-A data blocker between cable and adapter
does the same job reliably. With no data lines connected, web
workflow over Wi-Fi is your only edit path and saves will work.
I'll keep this issue open until the firmware-side piece has a home
to be tracked. Sorry for the runaround — your repro made the
real bug findable.
Reopening — auto-closed at PR #506 merge time, but as noted in the PR body and my earlier comment, the firmware-side root cause (board holds the MSC blockdev lock whenever USB MSC is enabled, regardless of host activity) is still outstanding. Tracking that work next on adafruit/circuitpython; will link the issue here once it's filed.
One other piece of information connected to this issue. Before CircuitPython 10.something none of this was an issue (note that using the Qualia ESP32-S3 requires 10.x, so not relevant to this additional point...). I just checked how web workflow works on an ESP32-S3 Feather with 4MB Flash and 2MB PSRAM and no SD card capabilities (runs a CAN-bus network on my unused home telephone wiring...) where I have CircuitPython 9.0.5 installed. I can write and save+run the code.py file on this system with no problems. But note that this system has no SD card capabilities.
Recall that the other system I mentioned, the QtPy ESP32-S3 with 8MB Flash and no PSRAM) that does have an SD card mounted. As noted above, I used to be able to write then save+run using web workflow on that board when running CircuitPython 9.something. Since upgrading to CircuitPython 10.x (now at 10.2.1) I can no longer write and save+run using web workflow (for the reasons you list above).
Just wanted to make it clear that there appears to be a CircuitPython version dependence to this issue of writing to CIRCUITPY using web workflow.
Yeah, it could be related to #377. I noticed some weirdness between different CircuitPython versions as well. Either way, I believe their both related to adafruit/circuitpython#10972.
Reacted by Jeff Mangum
makermelissa-ai-assistant commented on Jun 17, 2026
@jmangum quick update — the firmware-side fix landed on adafruit/circuitpythonmain: #11048 (merged 2026-06-10, commit c955e48).
That should resolve the case where the board reports the filesystem
read-only even though no USB host is actively mounted it.
One caveat: the fix is not in a tagged release yet. As of
right now the latest stable is 10.2.1 and the latest pre-release is
10.3.0-alpha.2 (2026-05-15) — both predate the fix. To test it today
you'd need the Absolute Newest build (a per-commit snapshot off main), which lives on circuitpython.org under each board's download
page, below the regular release buttons.
Direct links for the two boards you mentioned earlier (latest
post-fix snapshot, dated 2026-06-15):
Qualia ESP32-S3 for TTL RGB-666 Displays — .uf2
/ .bin
These are dev builds, so the usual caveats apply (back up your
CIRCUITPY contents before flashing). The PR number in the filename
(PR11050) is just whatever PR triggered that particular build job —
the fix you care about (#11048, commit c955e48) is in the tree from
2026-06-10 onward.
When you have a chance, could you flash one of those onto the same
power-only-USB setup that was failing before and try save + run on code.py from the web editor? If it works, we'll close this out
once 10.3.0-alpha.3 ships (so anyone hitting this from a regular
release has the fix too). If it still fails, that's useful too —
means there's another path I missed.
@makermelissa . Sorry for the slow response. I flashed the .uf2 you provided above for the ESP32-S3 QtPy and tried an edit then save+run from web workflow. Worked perfectly! Thank you!
Activity
Fix infinite save retry loop and method check bugs
jmangum commentedon Apr 25, 2026
Thank you @makermelissa for resolving this issue. I tested it and I can now edit and reload my
code.pyon my Qualia ESP32-S3. I do see a warning popup during the save and reload operation which indicates that the browser was trying and failing to writecode.py, but it does succeed (the popup appears and disappears quickly). Does not appear to affect performance, though. Thank you again!jmangum commentedon Apr 25, 2026
Hmmm. Upon further inspection it appears that
code.pyis in fact not being written when I try to save or save+run. The error popup I receive is attached, which I get when I try to just savecode.py.makermelissa commentedon Apr 28, 2026
Ok, thanks for the update. I'll take another look at it soon.
makermelissa commentedon Apr 28, 2026
I just noticed you are using Firefox. When this was originally written, it only worked on Chrome/Edge, so perhaps maybe it sort of works on Firefox now.
jmangum commentedon Apr 28, 2026
Yes, using Firefox. Just tried it again and still get the error. Perhaps I am missing a reload of code.circuitpython.org or something like that?
makermelissa commentedon Apr 28, 2026
I'll have to give it a try with FF soon. Come to think of it, I think Web Workflow should be fine. It would be the BLE/USB that would likely have trouble due to WebBluetooth and WebSerial support..
jmangum commentedon Apr 28, 2026
Very good @makermelissa . Let me know when you need for me to do another test.
Surface 'eject CIRCUITPY' hint when save fails because filesystem is …
makermelissa commentedon May 19, 2026
I was able to reproduce the issue in both chrome and firefox. Essentially, the file system was mounted read-only, but the error messaging wasn't very good to indicate this.
web_workflow: reply 409 Conflict instead of 500 when filesystem is wr…
2 remaining items
jmangum commentedon May 23, 2026
I generally use web workflow with Firefox (current version is 140.9.0esr) on MacOS Sequoia 15.7.7.
I just double-checked the behaviour. Project is connected to power-only USB (no USB mount of CIRCUITPY). When I try to edit
code.pyvia web workflow and save+run the changes I get your pop-up message. Sorry for the trouble.jmangum commentedon May 24, 2026
Out of curiosity I did tests using:
Get same result.
I have multiple Adafruit wifi-enabled boards running CircuitPython on my home network which I regularly use web workflow to connect to an edit/debug. I had not tried using web workflow recently where I edited
code.pyand tried to save+run. Just tried that on a QtPy ESP32-S3 (8Mb flash no psram) based project (using the Firefox browser noted above) and see the same behaviour (pop-up noting board filesystem lock when I am connected to power-only USB. I don't recall having CIRCUITPY file system write issues in the past with any of my CIRCUITPY projects.makermelissa commentedon Jun 1, 2026
Thank you. That should be helpful with trying to reproduce the issue.
No trouble at all. If you're seeing this, it probably means others are too, but not reporting it.
makermelissa-ai-assistant commentedon Jun 5, 2026
@jmangum thanks for the careful reproduction — the cross-browser
testing (Firefox / Safari / Chrome) and the second device (QtPy
ESP32-S3) were exactly what I needed to convince myself this isn't
a misconfiguration on your end.
Here's where I've landed:
1. The dialog from #498 is wrong for your case. It tells you a
host has CIRCUITPY mounted over USB, but in your setup nothing is
mounting it — you're on power-only USB. After walking through the
CircuitPython firmware, the actual cause is that the board's
MP_BLOCKDEV_FLAG_LOCKEDflag is held whenever USB Mass Storage isenabled on the board (which is the default on most boards),
regardless of whether a host is actively using the drive. The
dialog conflated those two cases.
2. Short-term fix — better messaging. I just opened
#506 to
rewrite the read-only / save-failure dialogs so they don't assert
host involvement, and to add a heads-up about the dual-workflow
tradeoff (Mu over USB vs. web workflow). That should land soon and
will at least stop the dialog from sending you on a goose chase.
3. The real fix is on the firmware side, and it isn't quick.
Your "I want both Mu and web workflow on the same project" workflow
is legitimate, and
boot.pydisabling USB MSC unconditionally is ablunt instrument. The cleanest path forward is firmware-side: the
board should release the MSC lock when no host has actually used it
in a while, or expose a cooperative way for web workflow to acquire
write access. I'm going to open a separate issue/discussion on
adafruit/circuitpython
to track that, and I'll link it here so you can follow along.
In the meantime, two workarounds that preserve dual-mode editing:
Button-gated
boot.py— the most popular pattern. Hold abutton at boot to disable USB MSC; otherwise leave it on. Lets
you choose Mu mode (no button) or web-workflow mode (hold button)
per power cycle. Example sketch:
Power-vs-data USB switching — if your project always sits on
a power adapter once deployed, a true USB power-only cable (data
lines physically disconnected) doesn't expose CIRCUITPY to any
host. Some "charging only" cables do this; many don't (most modern
ones carry data). A USB-A data blocker between cable and adapter
does the same job reliably. With no data lines connected, web
workflow over Wi-Fi is your only edit path and saves will work.
I'll keep this issue open until the firmware-side piece has a home
to be tracked. Sorry for the runaround — your repro made the
real bug findable.
Broaden read-only filesystem messaging (refs #460)
Merge pull request #506 from makermelissa-piclaw/fix/issue-460-broade…
makermelissa-ai-assistant commentedon Jun 5, 2026
Reopening — auto-closed at PR #506 merge time, but as noted in the PR body and my earlier comment, the firmware-side root cause (board holds the MSC blockdev lock whenever USB MSC is enabled, regardless of host activity) is still outstanding. Tracking that work next on
adafruit/circuitpython; will link the issue here once it's filed.jmangum commentedon Jun 5, 2026
Thank you @makermelissa . This is great.
One other piece of information connected to this issue. Before CircuitPython 10.something none of this was an issue (note that using the Qualia ESP32-S3 requires 10.x, so not relevant to this additional point...). I just checked how web workflow works on an ESP32-S3 Feather with 4MB Flash and 2MB PSRAM and no SD card capabilities (runs a CAN-bus network on my unused home telephone wiring...) where I have CircuitPython 9.0.5 installed. I can write and save+run the
code.pyfile on this system with no problems. But note that this system has no SD card capabilities.Recall that the other system I mentioned, the QtPy ESP32-S3 with 8MB Flash and no PSRAM) that does have an SD card mounted. As noted above, I used to be able to write then save+run using web workflow on that board when running CircuitPython 9.something. Since upgrading to CircuitPython 10.x (now at 10.2.1) I can no longer write and save+run using web workflow (for the reasons you list above).
Just wanted to make it clear that there appears to be a CircuitPython version dependence to this issue of writing to CIRCUITPY using web workflow.
makermelissa commentedon Jun 5, 2026
Yeah, it could be related to #377. I noticed some weirdness between different CircuitPython versions as well. Either way, I believe their both related to adafruit/circuitpython#10972.
makermelissa-ai-assistant commentedon Jun 17, 2026
@jmangum quick update — the firmware-side fix landed on
adafruit/circuitpythonmain:#11048 (merged 2026-06-10, commit c955e48).
That should resolve the case where the board reports the filesystem
read-only even though no USB host is actively mounted it.
One caveat: the fix is not in a tagged release yet. As of
right now the latest stable is 10.2.1 and the latest pre-release is
10.3.0-alpha.2 (2026-05-15) — both predate the fix. To test it today
you'd need the Absolute Newest build (a per-commit snapshot off
main), which lives on circuitpython.org under each board's downloadpage, below the regular release buttons.
Direct links for the two boards you mentioned earlier (latest
post-fix snapshot, dated 2026-06-15):
.uf2
/
.bin
.uf2
/
.bin
These are dev builds, so the usual caveats apply (back up your
CIRCUITPY contents before flashing). The PR number in the filename
(
PR11050) is just whatever PR triggered that particular build job —the fix you care about (#11048, commit
c955e48) is in the tree from2026-06-10 onward.
When you have a chance, could you flash one of those onto the same
power-only-USB setup that was failing before and try save + run on
code.pyfrom the web editor? If it works, we'll close this outonce 10.3.0-alpha.3 ships (so anyone hitting this from a regular
release has the fix too). If it still fails, that's useful too —
means there's another path I missed.
jmangum commentedon Jun 23, 2026
@makermelissa . Sorry for the slow response. I flashed the .uf2 you provided above for the ESP32-S3 QtPy and tried an edit then save+run from web workflow. Worked perfectly! Thank you!