siyuan-note/siyuan · error
decode HEIF image
Error message
decode HEIF image: %w
What it means
decodeImage wraps a failure from goheic.DecodeBytes (full pixel decode) as "decode HEIF image: %w", preserving the cause via %w. DecodeConfig succeeded (dimensions valid), but the actual lossy/lossless decode failed — e.g. frame size limit exceeded at full decode, unsupported codec profile, or decoder thread/alloc failure. Raised to convert and ImageSize callers.
Solutions
- Read the wrapped cause (errors.Unwrap) to distinguish profile-unsupported vs corrupt data
- Re-encode the image to a standard 8-bit HEIC or JPEG using an external tool and re-import
- Retry once in case of transient memory/alloc failure; if persistent, mark the asset corrupt
Example fix
// before
result, err := heif.GetOrCreate(ctx, data, opts)
if err != nil { return err }
// after
result, err := heif.GetOrCreate(ctx, data, opts)
if err != nil {
if strings.Contains(err.Error(), "decode HEIF image:") {
return fmt.Errorf("HEIF decode failed (unsupported profile or corrupt data): %v", err)
}
return err
} Defensive patterns
Strategy: try-catch
Try / catch
result, err := heif.GetOrCreate(ctx, data, opts)
if err != nil {
if strings.Contains(err.Error(), "decode HEIF image:") && !strings.Contains(err.Error(), "dimensions") {
// full decode failed after header ok: unsupported profile or corrupt payload
}
return err
} Prevention
- Prefer standard 8-bit SDR HEIC assets; exotic HDR/sequence profiles may not decode
- Retry once for transient alloc failures, then mark corrupt
- Unwrap the error to read the goheic cause for triage
When it happens
Trigger: goheic.DecodeBytes returns error for a container whose header parsed fine: unsupported HEVC/AV1 profile, decoder-internal frame size limit hit despite validDimensions, corrupted tile data after the header.
Common situations: Exotic HEIF profiles (10-bit HDR, image sequences, aux images) the decoder rejects, bit-rot or bit-flips in compressed payload, decoder resource limits under memory pressure.
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
- decode HEIF image
- read HEIF image dimensions
- avif: exif data too short
- decode image failed
- empty HEIF image
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/49b1698257d367d4.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/heif/convert.go:198
err = fmt.Errorf("decode HEIF image: %v", recovered)
}
}()
config, err := goheic.DecodeConfigBytes(source)
if err != nil {
return nil, fmt.Errorf("read HEIF image dimensions: %w", err)
}
if !validDimensions(config.Width, config.Height) {
return nil, ErrImageTooLarge
}
img, err = goheic.DecodeBytes(source, goheic.Options{
AutoRotate: true,
FrameSizeLimit: maxPixels,
Threads: 1,
})
if err != nil {
return nil, fmt.Errorf("decode HEIF image: %w", err)
}
return img, nil
}
func validDimensions(width, height int) bool {
return width > 0 && height > 0 && width <= maxDimension && height <= maxDimension &&
uint64(width)*uint64(height) <= uint64(maxPixels)
}
func estimatedJPEGSize(img image.Image) int {
pixels := int64(img.Bounds().Dx()) * int64(img.Bounds().Dy())
estimate := pixels / 2
if estimate < 64*1024 {
estimate = 64 * 1024
}
if estimate > 32*1024*1024 {
estimate = 32 * 1024 * 1024
}View on GitHub (pinned to 9f775e8a12)