siyuan-note/siyuan · warning

avif: invalid exif ifd offset

Error message

avif: invalid exif ifd offset

What it means

The EXIF header's IFD offset field (at TIFF offset 4) must be at least 8 (past the header itself) and within the payload bounds. parseExifData read an offset pointing before the header or beyond the data, so the IFD (directory of tags) cannot be located. This indicates a corrupt or maliciously crafted EXIF block.

Source

Thrown at kernel/heif/internal/h265heic/exif.go:291

		return errors.New("avif: exif data too short")
	}

	r := &exifReader{data: data}
	switch {
	case data[0] == 'I' && data[1] == 'I':
		r.littleEndian = true
	case data[0] == 'M' && data[1] == 'M':
	default:
		return errors.New("avif: invalid exif byte order marker")
	}

	if r.uint16(2) != 42 {
		return errors.New("avif: invalid exif magic number")
	}

	ifdOffset := r.uint32(4)
	if ifdOffset < 8 || int(ifdOffset) >= len(data) {
		return errors.New("avif: invalid exif ifd offset")
	}

	exifIFDOffset, gpsIFDOffset := parseIFD(r, int(ifdOffset), exif)
	if exifIFDOffset > 0 {
		parseExifSubIFD(r, exifIFDOffset, exif)
	}
	if gpsIFDOffset > 0 {
		parseGPSSubIFD(r, gpsIFDOffset, exif)
	}

	return nil
}

// eachEntry walks the entries of an IFD, resolving each value to its offset.
func eachEntry(r *exifReader, offset int, fn func(tag, dataType uint16, count uint32, valueOffset int)) {
	if offset < 0 || offset+1 >= len(r.data) {
		return
	}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Check whether the writer used file-relative IFD offsets that need rebasing to the payload start
  2. Validate the payload is complete (compare item extent length against declared offsets) before parsing
  3. Treat EXIF as unreadable and render the image with default orientation
  4. Sanitize/strip EXIF and re-export the file if the source is untrusted

Example fix

// before
ifdOffset := r.uint32(4)
// after
ifdOffset := r.uint32(4)
// writers sometimes emit offsets relative to the TIFF header start; rebase
if ifdOffset < 8 && ifdOffset+8 < uint32(len(data)) {
	ifdOffset += 8
}
Defensive patterns

Strategy: validation

Validate before calling

func hasBoundedIFD(data []byte) bool {
	if len(data) < 8 {
		return false
	}
	r := newExifReader(data)
	off := r.uint32(4)
	return off >= 8 && int(off) < len(data)
}

Type guard

func safeIFDOffset(data []byte) (int, bool) {
	if len(data) < 8 {
		return 0, false
	}
	off := int(binary.BigEndian.Uint32(data[4:8]))
	if off < 8 || off >= len(data) {
		return 0, false
	}
	return off, true
}

Try / catch

if err != nil && strings.Contains(err.Error(), "invalid exif ifd offset") {
	log.Warnf("EXIF IFD offset out of bounds; skipping metadata: %v", err)
	return nil
}

Prevention

When it happens

Trigger: DecodeExif on a payload where the uint32 at offset 4 is < 8 or >= len(data) — truncated EXIF payloads where the header claims offsets into data that was cut off, or crafted values.

Common situations: Truncated sync/download cutting the EXIF payload after the header; writers emitting offsets relative to the wrong base (common off-by-8 confusion between file-relative and item-relative offsets).

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/578e93122563d90c. Report an issue: GitHub.