{"record":{"id":"13ce6d71fbebcd0f","repo":"embassy-rs/embassy","slug":"cracen-rng-health-test-failed-rep-prop-star","errorCode":null,"errorMessage":"CRACEN RNG health test failed (rep={} prop={} startup={}); it needs a reset to produce entropy again","messagePattern":"CRACEN RNG health test failed \\(rep=(.+?) prop=(.+?) startup=(.+?)\\); it needs a reset to produce entropy again","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"embassy-nrf/src/cracen.rs","lineNumber":128,"sourceCode":"\n        self.start_rng();\n\n        let r = Self::core();\n        for chunk in dest.chunks_mut(4) {\n            // A failed health test parks the FSM in `Error`, where the FIFO never fills\n            // again — so without this check the poll never returns, and being a blocking\n            // loop in a sync fn it takes the whole executor with it. There is nothing to\n            // do but fail loudly: measured on an nRF54LM20A, neither a SoftRst nor\n            // reprogramming the cut-offs revives a TRNG that has already reached `Error`,\n            // only a reset of the part does, and an infallible API cannot report. The\n            // cut-offs programmed in `start_rng` are what keeps this unreached.\n            let word = loop {\n                if r.rngcontrol().fifolevel().read() != 0 {\n                    break r.rngcontrol().fifo(0).read();\n                }\n                let status = r.rngcontrol().status().read();\n                if status.state() == pac::cracencore::vals::State::Error {\n                    panic!(\n                        \"CRACEN RNG health test failed (rep={} prop={} startup={}); it needs a reset to produce entropy again\",\n                        status.repfail(),\n                        status.propfail(),\n                        status.startupfail()\n                    );\n                }\n            };\n\n            let word = word.to_ne_bytes();\n            let to_copy = word.len().min(chunk.len());\n            chunk[..to_copy].copy_from_slice(&word[..to_copy]);\n        }\n\n        self.stop_rng();\n    }\n\n    /// Generate a random u32\n    pub fn blocking_next_u32(&mut self) -> u32 {","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-nrf/src/cracen.rs#L110-L146","documentation":"The CRACEN hardware true-random-number-generator on nRF54-series reports a health-test failure (repetitive-count, adaptive-proportion, or startup test) through the RNGCONTROL status register. embassy-nrf's CsRng checks this in blocking_fill_bytes and panics because once the health test fails, the entropy source cannot produce trustworthy randomness until the whole chip is reset. Any RNG consumer (TLS keys, UUIDs, etc.) must never receive data from a failed RNG.","triggerScenarios":"Calling `CsRng::fill_bytes`, `try_fill_bytes`, `blocking_fill_bytes`, `blocking_next_u32`, or `blocking_next_u64` when `rngcontrol.status().state()` is `Error` — i.e. repfail, propfail, or startupfail bits are set after power-up or during operation.","commonSituations":"Startup failure right after boot due to marginal analog conditions/power supply noise; very early reads before the startup health test completes; rare silicon/environmental health-test failures in the field; unusual operating temperature or voltage conditions on nRF54L15 targets.","solutions":["Reset the chip (soft or hard reset) — the CRACEN RNG requires a reset to recover and produce entropy again","Delay first RNG use until the CRACEN RNG has fully started, and check status before use","Investigate power supply stability and operating conditions if startup failures recur on specific boards","Check for known silicon errata for your nRF54 revision and apply the recommended workaround","Retry with a fresh boot and, if reproducible, report to Nordic support with the rep/prop/startup fail bits"],"exampleFix":"null","handlingStrategy":"fallback","validationCode":"// Probe RNG health before deriving keys where the HAL exposes try_ APIs:\n// let mut probe = [0u8; 4];\n// match rng.try_fill_bytes(&mut probe) { Ok(_) => {}, Err(_) => schedule_reset() }","typeGuard":null,"tryCatchPattern":"// The HAL panics on failure; there is no catchable error. Use a fallback:\n// match rng.try_fill_bytes(&mut buf) {\n//     Ok(()) => buf,\n//     Err(_) => { defmt::error!(\"CRACEN RNG failed, scheduling reset\"); board_reset(); unreachable!() }\n// }","preventionTips":["Delay first entropy use until after peripheral startup completes","Monitor supply voltage/temperature if failures appear in the field","Check nRF54 errata for your silicon revision","Treat any RNG panic as fatal: reset the chip, never continue with partial entropy"],"tags":["rng","embedded","nrf","cracen","entropy","security"],"backgroundTag":"rng-health-test-failed","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"}