juicedata/juicefs · error

failed to read footer length: err %w, read len %d, expect le

Error message

failed to read footer length: err %w, read len %d, expect len %d

What it means

BakFooter.Unmarshal reads the last 8 bytes of the stream to obtain the footer length. If the read errors or returns fewer bytes than requested, the file is too short or unreadable and this wrapped error is returned, preventing footer parsing.

Source

Thrown at pkg/meta/backup.go:204

	if n, err := w.Write(data); err != nil && n != len(data) {
		return fmt.Errorf("failed to write footer data: err %w, write len %d, expect len %d", err, n, len(data))
	}

	h.Len = uint64(len(data))
	if n, err := w.Write(binary.BigEndian.AppendUint64(nil, h.Len)); err != nil && n != 8 {
		return fmt.Errorf("failed to write footer length: err %w, write len %d, expect len 8", err, n)
	}
	return nil
}

func (h *BakFooter) Unmarshal(r io.ReadSeeker) error {
	lenSize := int64(unsafe.Sizeof(h.Len))
	_, _ = r.Seek(-lenSize, io.SeekEnd)

	data := make([]byte, lenSize)
	if n, err := r.Read(data); err != nil && n != int(lenSize) {
		return fmt.Errorf("failed to read footer length: err %w, read len %d, expect len %d", err, n, lenSize)
	}

	h.Len = binary.BigEndian.Uint64(data)
	_, _ = r.Seek(-int64(h.Len)-lenSize, io.SeekEnd)
	data = make([]byte, h.Len)
	if n, err := r.Read(data); err != nil && n != int(h.Len) {
		return fmt.Errorf("failed to read footer: err %w, read len %d, expect len %d", err, n, h.Len)
	}

	h.Msg = &pb.Footer{}
	if err := proto.Unmarshal(data, h.Msg); err != nil {
		return fmt.Errorf("failed to unmarshal footer: %w", err)
	}
	return nil
}

type BakSegment struct {
	typ uint32

View on GitHub (pinned to c9a67b23e8)

Solutions

  1. Verify the backup file size and integrity; re-transfer it
  2. Regenerate the backup with juicefs dump
  3. Check the source storage for read errors (dmesg, object storage consistency)
Defensive patterns

Strategy: validation

Validate before calling

fi, err := os.Stat(bakPath)
if err != nil {
    return err
}
if fi.Size() < 8 {
    return fmt.Errorf("%s too small to contain a footer", bakPath)
}

Type guard

func plausiblyBackup(path string) bool {
    fi, err := os.Stat(path)
    return err == nil && fi.Size() > 8
}

Try / catch

footer, err := f.ReadFooter(rs)
if err != nil {
    if strings.Contains(err.Error(), "failed to read footer length") {
        return fmt.Errorf("backup file truncated or unreadable: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: ReadFooter → BakFooter.Unmarshal on a file smaller than 8 bytes, a truncated backup, or an unreadable/corrupt tail region (I/O error from the underlying ReadSeeker).

Common situations: Pointing summary/load at a truncated or partially uploaded backup file; a zero-byte or wrong file passed to juicefs load/summary; storage-level corruption at the file tail.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06). Data as JSON: /api/errors/038f623fe9477416. Report an issue: GitHub.