fix(luks): surface cryptsetup error output when unlock fails - #4570
Merged
Conversation
Luks2.unlock() ran 'cryptsetup open' with no error handling, so a failure raised a bare CalledProcessError. Python renders that exception with only the exit status and discards the captured output, so cryptsetup's stderr (merged into stdout by run()) never reached the install log. encrypt() already wraps its cryptsetup call and raises a DiskError that includes the captured output. Mirror that for unlock() so a failure reports the actual cryptsetup message instead of an opaque traceback. Reported in archlinux#4327, where the underlying 'device-mapper: crypt: unknown table type' error was hidden from the log for this reason.
svartkanin
approved these changes
Jun 6, 2026
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.
What
Luks2.unlock()callscryptsetup openthroughrun()with no error handling. When the command fails it raises a bareCalledProcessError, and Python's default rendering of that exception prints only the exit status (returned non-zero exit status N) while discarding the captured output. Sincerun()setsstderr=subprocess.STDOUT, that discarded output is exactly cryptsetup's stderr, so the real diagnostic never reachesinstall.log.This wraps the call and raises a
DiskErrorthat includes the captured output, mirroring whatencrypt()already does a few lines above in the same file:Why
Reported in #4327: a manually partitioned encrypted btrfs install failed at "unlocking luks2 device" with only a traceback ending in
returned non-zero exit status 5. The reporter noted that the log did not include the stderr of cryptsetup and had to re-run the command by hand to discover the actual cause (device-mapper: crypt: unknown table type). With this change that message would have been written straight to the install log.This does not try to fix the underlying device-mapper condition in #4327, which looks environmental and was not reproducible by other contributors. It makes that whole class of unlock failure diagnosable from the log instead of opaque.
Notes
DiskErrorinstead of an uncaughtCalledProcessError.encrypt()error handling in the same module.ruff checkandruff format --checkpass.