How to fix Apple Books EPUBs that won't open anywhere else
I picked up an iFlytek AINote Air 2 recently (an e-ink reader and writing tablet) and I’ve been slowly moving my reading over to it. Sideloading EPUBs is straightforward in theory. In practice, the first book I tried to copy off Apple Books refused to open.
The file had a .epub extension. It looked fine. Every validator I threw at it disagreed.
What Apple Books actually does on disk
Apple Books does not store EPUBs as zip files. It unzips them into a folder structure internally and never bothers to re-zip them when you export. So when you copy what looks like an EPUB out of your Books library, you’re getting a broken archive that fails spec.
The specific violation: EPUB requires the mimetype file to be the very first entry in the zip, and it must be stored uncompressed. Apple’s export breaks both.
Validators will flag this immediately. Readers that follow the spec will refuse to open the file. The AINote Air 2 is one of them.
The fix
Navigate into the unzipped book folder (or the exported EPUB if it extracted on copy) and run this:
zip -X0 MyBook.epub mimetype
zip -r9 MyBook.epub * -x mimetype -x "*.DS_Store"
Or as a one-liner:
zip -X0 MyBook.epub mimetype && zip -r9 MyBook.epub * -x mimetype -x "*.DS_Store"
What those flags do:
-Xstrips extra file attributes like Unix UID/GID that EPUB readers can choke on-0storesmimetypewith no compression (required by the spec)-rrecurse into subdirectories for the rest of the contents-9max compression for everything exceptmimetype-x "*.DS_Store"drops macOS hidden files that will fail validation on other systems
The two-command approach is intentional. You’re building the archive in two passes: first the mimetype entry, uncompressed and first in the archive, then everything else on top. The one-liner does the same thing; pick whichever reads more clearly to you.
After repackaging
The resulting MyBook.epub passes epubcheck validation and opens cleanly on the AINote Air 2. I’ve run a handful of Apple Books exports through this now and it works consistently.
The part that still mildly annoys me: Apple Books has had this broken export behavior for years. The fix is well-documented in various forums. Apple has not fixed it. At some point you stop waiting and just write the script.
Oh by the way, want the script?
If you do this more than once, here is the same fix as a small script. Save it as fixepub.sh, chmod +x fixepub.sh, then run it.
#!/usr/bin/env bash
# fixepub.sh -- repackage an EPUB so mimetype is the first uncompressed entry.
# Usage: fixepub.sh input.epub [output.epub]
set -euo pipefail
INPUT="${1:?usage: fixepub.sh input.epub [output.epub]}"
OUTPUT="${2:-${INPUT%.epub}-fixed.epub}"
OUTPUT_ABS=$(cd "$(dirname "$OUTPUT")" && pwd)/$(basename "$OUTPUT")
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT
unzip -q "$INPUT" -d "$TMPDIR"
cd "$TMPDIR"
rm -f "$OUTPUT_ABS"
zip -X0 "$OUTPUT_ABS" mimetype
zip -r9 "$OUTPUT_ABS" . -x mimetype -x "*.DS_Store"
echo "Fixed: $OUTPUT_ABS"
Example:
./fixepub.sh broken.epub
# outputs: broken-fixed.epub next to the input
./fixepub.sh broken.epub ~/Desktop/clean.epub
# outputs to a specific path
The trap cleans up the temp directory whether the script exits cleanly or not. Filenames with spaces work fine. No dependencies beyond bash, unzip, and zip, all of which ship with macOS and most Linux distributions.