The safe answer is to keep three artifacts separate: the readable source, an approved UTF-8 copy, and the EPUB built from that copy. Do not overwrite the source merely because a wrongly decoded window appears editable. Identify the source encoding first, decide any character substitutions as editorial changes, write the approved text to a new filename, and reopen that file before it becomes EPUB input.
This article shows how to export UTF-8 EPUB without garbled text by following one recorded sample from inspection through package validation. The point is not to offer a universal “fix encoding” button. It is to make the input decision reproducible, with an exact command, observed values, a failure state, a recovery point, and a release condition.
Divide the symptom before changing a file
Ask where the corruption first appears. If the source is already unreadable when opened, investigate decoding and the authority of the source. If the source is readable but the packaged book is not, investigate which copy entered the EPUB and what its XHTML contains. Treating both symptoms as one problem makes it impossible to tell whether a save operation or the packaging step changed the text.
The controlled run used three independent files named source-UTF-8.txt, source-Shift_JIS.txt, and source-UTF-16LE.txt. They held the same short Japanese sample but intentionally used different byte encodings. That separation matters: a readable window is an observation, while a filename paired with an encoding inspection is evidence that another editor can check.
Do not delete an unusual character merely to reach zero warnings. Record the surrounding sentence and decide what the author intended. A name variant, a historical form, and a decorative symbol require different editorial decisions. Encoding determines how approved text is represented; it does not determine what the approved text should say.
Inspect all inputs with one command shape
For the UTF-8 sample, the recorded command was rune inspect text --file /private/tmp/rune-g2c3-studio-276-qfiw6clt/source-UTF-8.txt --json. The Shift_JIS and UTF-16LE checks used the same command with only the filename changed. Every recorded command exited with code 0.
The persisted results were specific. The UTF-8 file returned encoding=UTF-8, lineEnding=LF, and 44 characters. The Shift_JIS file returned encoding=Shift_JIS, LF, and 44 characters. The UTF-16LE file returned encoding=UTF-16LE, LF, and 45 characters. The last count is not silently normalized to 44; it is part of the observed result and must be explained before that source is approved.
Stop here if the detected encoding differs from the expected source, the line ending changes unexpectedly, or the decoded string does not match the authority. The recovery action is to select the readable source again and create another working copy. Overwriting the suspicious file would remove the evidence needed to diagnose the wrong decoder or the wrong source selection.
Write an approved copy without touching the authority
The output name in the run was STUDIO-276-converted-copy.txt. Before writing, the test executed rune file write --path /private/tmp/rune-g2c3-studio-276-qfiw6clt/STUDIO-276-converted-copy.txt --content-file /private/tmp/rune-g2c3-studio-276-qfiw6clt/approved-utf8-content.txt --dry-run --json. Only after the dry run named the intended target did the run repeat the command without --dry-run.
The command deliberately names two different files: an approved-content input and a converted-copy output. The original source is neither. That simple naming rule makes the rollback obvious. If the saved result is bad, discard or retain that result for comparison; do not attempt to reconstruct the authority from it.
A successful write response is an intermediate state. The run closed the loop with rune inspect text --file /private/tmp/rune-g2c3-studio-276-qfiw6clt/STUDIO-276-converted-copy.txt --json. The reopened file reported UTF-8, LF, and 44 characters. Its SHA-256 was a0c4bad89b08523b704e04e7dbdee7e141327cfe719f993d59919e351ffbdbea, identical to the approved UTF-8 content, and the decoded strings compared equal.
Character count alone is not enough. Two strings can contain the same number of characters and still differ at a name, punctuation mark, or combining sequence. The acceptance rule therefore requires both the structural readback and decoded-text equality. When equality fails, retain the failed copy, correct the editorial decision in a newly named input, and run the inspection again.
Feed only that copy into the EPUB build
The package lane used three chapter files and set the series with --writing-mode horizontal --language ja. It then set volume 0 to EPUB version 3.1, selected the three files, obtained an export plan, exported deterministically, and inspected the resulting EPUB. Those are separate commands because a plan is not a generated book and an export response is not a package inspection.
The persisted package is studio-276-260903.120000.epub, with SHA-256 078c961833b1b9d179f3da1ffaf8d545cc2cd3a23f63468cfa200771ec0e4fc8. Local inspection returned valid=true. The package contained three chapter entries in its reading order, three navigation links, matching NCX points, Japanese metadata, and no reported missing resource.
This package result is useful only when it is tied to the accepted UTF-8 input. A valid container built from the wrong manuscript is still the wrong book. Preserve the input hash and the EPUB hash as two different facts, so a later editor can identify exactly which source produced a given package.
The release condition for this workflow is therefore conjunctive: the separately named file reopens as UTF-8/LF with decoded text equal to the approval source, and the EPUB generated from that approved copy passes the recorded local structure inspection. If the first condition fails, return to source selection. If the second fails, keep the approved text and troubleshoot packaging instead of repeating conversion.
Keep documentation claims outside the measured lane
Rune Studio's public documentation describes detection of major Japanese encodings, graphical highlighting of unrepresentable characters, and suspension of automatic saving while unresolved characters remain. The command-driven run above measured file inspection, writing, reopening, and EPUB structure. It did not measure highlight pixels, IME behavior, the autosave timer, selection state, or an unsaved memory buffer. Those documented interface capabilities must not be presented as observations from this CLI run.
Nor does valid=true prove retailer acceptance or identical typography on every reading system. KDP approval, device rendering, OCR, and recovery of already corrupted binary data are outside this test. They require their own evidence and should not be smuggled into a conclusion about source encoding.
Finish with three clearly named artifacts: the unchanged readable source, the approved 44-character UTF-8 copy, and the inspected EPUB. That arrangement gives every failure a safe return point. Check the current Rune Studio feature scope for the documented Mac capabilities, then prove the workflow on a short copied chapter before applying it to an entire manuscript.