siyuan-note/siyuan · error
ErrInvalidMode
ErrInvalidMode
Error message
invalid HEIF conversion mode
What it means
ErrInvalidMode is returned when Options.Mode is neither ModePreview nor ModeThumbnail. GetOrCreate validates the mode before decoding, and convert re-validates it. It is a programming/API-misuse sentinel: only the two exported Mode values are accepted.
Source
Thrown at kernel/heif/convert.go:54
previewQuality = 90
thumbnailQuality = 85
MaxInputBytes = 32 * 1024 * 1024
maxDimension = 65535
desktopMaxPixels = 50_000_000
mobileMaxPixels = 12_500_000
// 解码层仅接受至多 10-bit 4:2:0、无透明通道的单 slice 图像;这里按解码面、CTU 表、
// NRGBA 和一次合并变换预留每像素 16 字节,再单独预留源文件、RBSP 副本与 JPEG 输出。
workingBytesPerPixel = 16
desktopWorkingBudget = 960 * 1024 * 1024
mobileWorkingBudget = 320 * 1024 * 1024
desktopOutputReserve = 96 * 1024 * 1024
mobileOutputReserve = 32 * 1024 * 1024
)
var (
ErrInputTooLarge = errors.New("HEIF image exceeds the input size limit")
ErrImageTooLarge = errors.New("HEIF image exceeds the dimension limit")
ErrInvalidMode = errors.New("invalid HEIF conversion mode")
conversionSlots = make(chan struct{}, 1)
maxPixels = platformMaxPixels()
)
func platformMaxPixels() int {
if runtime.GOOS == "android" || runtime.GOOS == "ios" {
return pixelsWithinBudget(mobileWorkingBudget, mobileOutputReserve, mobileMaxPixels)
}
return pixelsWithinBudget(desktopWorkingBudget, desktopOutputReserve, desktopMaxPixels)
}
func ReadFileLimited(path string, maxBytes int64) ([]byte, error) {
if maxBytes <= 0 {
return nil, ErrInputTooLarge
}
file, err := os.Open(path)
if err != nil {View on GitHub (pinned to 8641553a1f)
Solutions
- Always set Options.Mode to heif.ModePreview or heif.ModeThumbnail using the exported constants, never raw strings.
- If Options is assembled dynamically, default to ModePreview when unset before calling GetOrCreate.
- Check string case and whitespace if the mode is derived from configuration; compare against the constants, not literals.
Example fix
// before
opts := heif.Options{Encrypted: true, BoxID: box} // Mode zero-value
res, err := heif.GetOrCreate(ctx, data, opts) // ErrInvalidMode
// after
opts := heif.Options{Mode: heif.ModeThumbnail, Encrypted: true, BoxID: box}
res, err := heif.GetOrCreate(ctx, data, opts) Defensive patterns
Strategy: type-guard
Validate before calling
func validMode(m heif.Mode) bool { return m == heif.ModePreview || m == heif.ModeThumbnail }
if !validMode(opts.Mode) { return errors.New("Options.Mode must be heif.ModePreview or heif.ModeThumbnail") } Type guard
func isConversionMode(m heif.Mode) bool {
return m == heif.ModePreview || m == heif.ModeThumbnail
} Try / catch
res, err := heif.GetOrCreate(ctx, data, opts)
if errors.Is(err, heif.ErrInvalidMode) {
opts.Mode = heif.ModePreview // safe default
res, err = heif.GetOrCreate(ctx, data, opts)
} Prevention
- Only assign mode values from the exported constants, never raw strings.
- Never build Options{} zero-value and call GetOrCreate directly; set Mode explicitly.
- Centralize Options construction in one helper so Mode is never forgotten.
- Guard with errors.Is(err, heif.ErrInvalidMode) in tests and fallback paths.
When it happens
Trigger: Calling heif.GetOrCreate with a zero-value Options{} (Mode is the empty string), or with a custom/typo'd mode string such as "full" or "Preview" (case-sensitive). Test TestGetOrCreateValidatesOptionsBeforeDecode relies on exactly this sentinel.
Common situations: Constructing Options{} partially and forgetting Mode; copying Options from a struct literal that omitted Mode; writing custom mode strings instead of using the heif.ModePreview/ModeThumbnail constants.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- invalid create attribute view item documents save mode [%s]
- unsupported block data type [%s]
- unsupported template render mode [%s]
- invalid agent runtime turn state
- invalid new item template target type [%s]
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/15ebc1376a07096d.
Report an issue: GitHub.