{"record":{"id":"75c3a455bb78cf36","repo":"siyuan-note/siyuan","slug":"decode-heif-image-v","errorCode":null,"errorMessage":"decode HEIF image: %v","messagePattern":"decode HEIF image: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/heif/convert.go","lineNumber":180,"sourceCode":"\tdefer func() {\n\t\t<-conversionSlots\n\t}()\n\timg, err := decodeImage(source)\n\tif err != nil {\n\t\treturn 0, 0, err\n\t}\n\twidth, height = img.Bounds().Dx(), img.Bounds().Dy()\n\tif !validDimensions(width, height) {\n\t\treturn 0, 0, ErrImageTooLarge\n\t}\n\treturn width, height, nil\n}\n\nfunc decodeImage(source []byte) (img image.Image, err error) {\n\tdefer func() {\n\t\tif recovered := recover(); recovered != nil {\n\t\t\timg = nil\n\t\t\terr = fmt.Errorf(\"decode HEIF image: %v\", recovered)\n\t\t}\n\t}()\n\n\tconfig, err := goheic.DecodeConfigBytes(source)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read HEIF image dimensions: %w\", err)\n\t}\n\tif !validDimensions(config.Width, config.Height) {\n\t\treturn nil, ErrImageTooLarge\n\t}\n\n\timg, err = goheic.DecodeBytes(source, goheic.Options{\n\t\tAutoRotate:     true,\n\t\tFrameSizeLimit: maxPixels,\n\t\tThreads:        1,\n\t})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"decode HEIF image: %w\", err)","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/heif/convert.go#L162-L198","documentation":"decodeImage recovers a panic from the internal HEIC decoder (which wraps cgo/libheif-style native code) and converts it into this error carrying the recovered value. Native decoders can panic (or crash) on malformed bitstreams, so the package deliberately converts panics into ordinary errors to protect the process.","triggerScenarios":"Any call path that reaches decodeImage — convert (ModePreview/ModeThumbnail) or ImageSize — where the internal decoder panics while parsing the HEIF/HEVC bitstream, e.g. malformed NAL units, corrupt VPS/SPS/PPS, or out-of-bounds access in native parsing.","commonSituations":"Corrupt or deliberately fuzzed .heic files; partially downloaded/truncated assets; files renamed to .heic that are not actually HEIF; unusual HEVC profiles the decoder mishandles.","solutions":["Treat the file as unrenderable and surface a user-facing 'cannot open this image' message","Check the recovered value in the message to see whether it is an out-of-range panic, nil deref, or native assertion","Verify the file opens in another HEIF viewer; if not, the file is corrupt","Report the file to maintainers if it decodes elsewhere — it may expose a decoder bug needing an upstream fix","Consider re-encoding the image with an external tool before importing"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if len(source) < 12 || string(source[4:8]) != \"ftyp\" {\n\treturn errors.New(\"not a HEIF container\")\n}","typeGuard":"func looksLikeHeif(b []byte) bool {\n\treturn len(b) >= 12 && string(b[4:8]) == \"ftyp\"\n}","tryCatchPattern":"if err != nil && strings.HasPrefix(err.Error(), \"decode HEIF image:\") {\n\tlog.Warnf(\"decoder panicked on HEIF input: %v\", err)\n\treturn errUnsupportedFile\n}","preventionTips":["Validate the ftyp brand before handing bytes to the decoder","Quarantine files that repeatedly panic and skip them in batch jobs","Report panic-inducing files upstream so the native parser gets fixed","Run batch conversions with per-file error isolation, not fail-fast"],"tags":["heif","panic-recovery","decoder","malformed-input"],"backgroundTag":"internal-invariant-violation","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}