Fix multipart parser truncating binary uploads ending in a whitespace byte (Image hash failed)#10
Open
HansStrupat wants to merge 1 commit into
Open
Conversation
The /api/flash and /api/firmware/upload multipart parsers call part.strip() on each raw part. bytes.strip() drops trailing ASCII-whitespace bytes (09 0a 0b 0c 0d 20), so any uploaded image whose final byte is whitespace is silently truncated -> its appended SHA-256 no longer matches -> the device boot-loops with "esp_image: Image hash failed - image is corrupt". It is content-dependent (~2-3% of builds at random) and independent of chip/board/baud/esptool, which makes it very hard to diagnose. Strip only the leading CRLF framing instead; the existing content.endswith(b"\r\n") check already removes the trailing framing CRLF. Applied at both multipart parsers. Fixes SensorsIot#9 Co-Authored-By: Claude Opus 4.8 (1M context) <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
/api/flashand/api/firmware/uploaduse a hand-rolled multipart parser that callspart.strip()on each raw part.bytes.strip()removes trailing ASCII-whitespace bytes(
09 0a 0b 0c 0d 20), so any uploaded binary whose final byte is whitespace is silentlytruncated. The flash then "succeeds" (esptool reports
Hash of data verifiedagainst thetruncated temp file), but the device boot-loops with:
because the appended SHA-256 no longer matches. It hits ~2–3% of builds at random and is
independent of chip / board / baud / esptool version — which makes it look board- or chip-specific
and very confusing to diagnose.
Reproduction
Same ESP32, same portal, only the app's last byte differs:
/api/flash0x20Image hash failed0xFF(after the SHA-256, ignored by the ROM)0xFFFlashing the original file with esptool directly on the Pi against the same
/dev/ttyUSB0boots fine at any baud, stub or
--no-stub— confirming the corruption is introduced by theparser, not esptool/serial.
Fix
Strip only the leading CRLF framing; never
.strip()the part body. The existingcontent.endswith(b"\r\n")check already removes the trailing framing CRLF, so the oldpart.strip()was both redundant and destructive. Applied at both parsers. (Thepart = part.strip()calls insidefor part in content_type.split(";")are unrelatedContent-Type header parsing and are left untouched.)
Verified
Applied to a running workbench (esptool v5.2.0, classic ESP32-D0WD over a CP2102,
/dev/ttyUSB0):the exact image that previously bricked on every
/api/flashnow boots, with no other changes.Fixes #9
🤖 Generated with Claude Code