{"record":{"id":"97f808d68109f5f1","repo":"embassy-rs/embassy","slug":"the-erase-sizes-for-the-concatenated-flashes-must","errorCode":null,"errorMessage":"The erase sizes for the concatenated flashes must have have a gcd equal to the max erase size","messagePattern":"The erase sizes for the concatenated flashes must have have a gcd equal to the max erase size","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-embedded-hal/src/flash/concat_flash.rs","lineNumber":39,"sourceCode":"    }\n    first_read_size\n}\n\nconst fn get_write_size(first_write_size: usize, second_write_size: usize) -> usize {\n    if first_write_size != second_write_size {\n        panic!(\"The write size for the concatenated flashes must be the same\");\n    }\n    first_write_size\n}\n\nconst fn get_max_erase_size(first_erase_size: usize, second_erase_size: usize) -> usize {\n    let max_erase_size = if first_erase_size > second_erase_size {\n        first_erase_size\n    } else {\n        second_erase_size\n    };\n    if max_erase_size % first_erase_size != 0 || max_erase_size % second_erase_size != 0 {\n        panic!(\"The erase sizes for the concatenated flashes must have have a gcd equal to the max erase size\");\n    }\n    max_erase_size\n}\n\nimpl<First, Second, E> ErrorType for ConcatFlash<First, Second>\nwhere\n    First: ErrorType<Error = E>,\n    Second: ErrorType<Error = E>,\n    E: NorFlashError,\n{\n    type Error = E;\n}\n\nimpl<First, Second, E> ReadNorFlash for ConcatFlash<First, Second>\nwhere\n    First: ReadNorFlash<Error = E>,\n    Second: ReadNorFlash<Error = E>,\n    E: NorFlashError,","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-embedded-hal/src/flash/concat_flash.rs#L21-L57","documentation":"`get_max_erase_size` requires the larger of the two ERASE_SIZE values to be divisible by both erase sizes, i.e. the max erase size equals the gcd. ConcatFlash must expose one ERASE_SIZE that covers both devices' erase alignment; if neither erase size divides the max, the invariant fails and it panics at const evaluation.","triggerScenarios":"`ConcatFlash::new(a, b)` where e.g. ERASE_SIZE values are 4096 and 65536? no — 65536%4096==0 passes; it fails for values like 4096 and 8192? also passes. It fails for mutually non-dividing sizes, e.g. 4096 and 6144, or 2048 and 4096 fails only when the smaller doesn't divide the larger (e.g. 3072 & 4096).","commonSituations":"Concatenating flash from different families with incompatible sector sizes (e.g. 4 KiB and 32 KiB subsectors that don't divide each other); off-brand SPI NOR with unusual sector sizes; changing the second flash in a design without re-checking erase alignment.","solutions":["Pick two flashes whose erase sizes divide evenly (one must be a multiple of the other)","Use a flash chip with a sector size that is a multiple of the other's","Add a software erase-size wrapper presenting a compatible ERASE_SIZE (translate erase addresses to the chip's sector grid)","Reduce to using only one flash type if alignment cannot be achieved"],"exampleFix":"// before\nlet flash = ConcatFlash::new(flash_a /* ERASE_SIZE=4096 */, flash_b /* ERASE_SIZE=6144 */); // 6144 % 4096 != 0\n// after\nlet flash = ConcatFlash::new(flash_a /* ERASE_SIZE=4096 */, flash_b /* ERASE_SIZE=8192 */); // 8192 % 4096 == 0","handlingStrategy":"validation","validationCode":"const fn erase_ok(a: usize, b: usize) -> bool {\n    let max = if a > b { a } else { b };\n    max % a == 0 && max % b == 0\n}\nconst _: () = assert!(erase_ok(FLASH_A_ERASE, FLASH_B_ERASE), \"erase sizes not aligned\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Select flash chips whose sector sizes divide evenly (one a multiple of the other)","Const-assert erase-size compatibility in board config","Use an erase-translating wrapper when chip sector grids differ","Check datasheet sector sizes when substituting flash hardware"],"tags":["embedded","flash","compile-time","panic","alignment"],"backgroundTag":"invalid-config-value","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}