juicedata/juicefs · error
failed to read footer: %w
Error message
failed to read footer: %w
What it means
`showBakSummary` reads the backup file's footer via meta.BakFormat.ReadFooter(fp). The footer is a length-prefixed protobuf record at the end of the file containing the backup version and per-segment info. If the footer cannot be read or decoded (corrupt, truncated, or not a JuiceFS backup file), the error is wrapped as `failed to read footer: <error>`.
Source
Thrown at cmd/load.go:283
defer fp.Close()
if !ctx.IsSet("offset") {
return showBakSummary(ctx, fp, false)
}
offset := ctx.Int64("offset")
if offset == -1 {
return showBakSummary(ctx, fp, true)
}
return showBakDetail(ctx, fp, offset)
}
func showBakSummary(ctx *cli.Context, fp *os.File, withOffset bool) error {
bak := &meta.BakFormat{}
footer, err := bak.ReadFooter(fp)
if err != nil {
return fmt.Errorf("failed to read footer: %w", err)
}
fmt.Printf("Backup Version: %d\n", footer.Msg.Version)
data := make([][]string, 0, len(footer.Msg.Infos))
for name, info := range footer.Msg.Infos {
if withOffset {
data = append(data, []string{name, fmt.Sprintf("%d", info.Num), fmt.Sprintf("%d", info.Offset)})
} else {
data = append(data, []string{name, fmt.Sprintf("%d", info.Num)})
}
}
sort.Slice(data, func(i, j int) bool {
return data[i][0] < data[j][0]
})
if withOffset {
fmt.Println(strings.Repeat("-", 34))
fmt.Printf("%-10s| %-10s| %-10s\n", "Name", "Num", "Offset")View on GitHub (pinned to c9a67b23e8)
Solutions
- Verify the file is a complete JuiceFS binary backup (check size against the source, re-download if needed)
- Confirm you are not passing a plain JSON dump — footers only exist in binary backups
- Decompress first if the backup is gzipped
- Re-create the backup with `juicefs dump --backup` and retry; if the version is newer, upgrade your JuiceFS client
Example fix
// before juicefs load --stat meta.sqlite3 backup.json.gz # still gzipped // after gunzip backup.json.gz && juicefs load --stat meta.sqlite3 backup.json
Defensive patterns
Strategy: validation
Validate before calling
fi, err := os.Stat(backupPath)
if err != nil { return err }
if fi.Size() < 64 { return fmt.Errorf("file too small to be a backup: %s", backupPath) }
if hasGzipMagic(backupPath) { return fmt.Errorf("decompress before inspecting") } Try / catch
if err := showSummary(fp); err != nil {
if strings.Contains(err.Error(), "failed to read footer") {
log.Fatalf("truncated/corrupt or non-binary backup: %v", err)
}
} Prevention
- Verify backup size/checksum after every dump or download
- Only feed binary backups to footer-parsing commands, not JSON dumps
- Decompress gzipped backups before inspection
- Keep client versions compatible with the backup writer version
When it happens
Trigger: Inspecting (`statBak`/summary) a file that is not a JuiceFS binary backup (e.g. a plain JSON dump, or a text file), or a backup that was truncated by an interrupted dump/transfer, or one whose trailing bytes were cut off.
Common situations: Downloading the backup from object storage incompletely; opening a gzipped backup without decompressing; a backup written by a much newer JuiceFS client with an incompatible footer version; corrupted file from a failed rsync.
Understand the failure class
Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.
Related errors
- The entry of the root inode was not found
- failed to read segment: %w
- unknown message type %d
- failed to unmarshal segment msg %d: %w
- not implemented, use kvMeta.LoadMetaV2 instead
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/99cdb396e9f66943.
Report an issue: GitHub.