{"record":{"id":"75c3a455bb78cf36","repo":"siyuan-note/siyuan","slug":"decode-heif-image-v","errorCode":null,"errorMessage":"decode HEIF image: %v","messagePattern":"decode HEIF image: (.+?)","errorType":"exception","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/9f775e8a12daef8255556097396f9b2739078892/kernel/heif/convert.go#L162-L198","documentation":"decodeImage recovers a panic from the vendored goheic decoder and converts it into this error (\"decode HEIF image: %v\" with the recovered value). This keeps malformed or hostile HEIF bitstreams from crashing the kernel with a panic. The %v formatting means the original panic value is not wrapped — match by prefix, not errors.Is.","triggerScenarios":"goheic.DecodeBytes (or related code inside decodeImage) panics on a corrupt, truncated, or malformed HEIF payload; the recover in decodeImage fires and returns this error.","commonSituations":"Fuzzed or corrupted .heic assets, files with valid headers but broken compressed payloads, goheic library bugs on exotic HEIF profiles (e.g. multi-image or depth maps).","solutions":["Treat the source file as corrupt: re-export/re-import the image from the original device","Inspect the recovered panic message to identify whether it is a known goheic limitation","Isolate the failing asset and reproduce with goheic directly; report upstream if it is a decoder bug"],"exampleFix":"// before\nimg, err := heif.ImageSize(data) // panics propagate in naive wrappers\n// after\nif _, err := heif.ImageSize(data); err != nil {\n\tif strings.HasPrefix(err.Error(), \"decode HEIF image:\") {\n\t\treturn fmt.Errorf(\"asset is corrupt or unsupported HEIF: %v\", err)\n\t}\n\treturn err\n}","handlingStrategy":"try-catch","validationCode":"// heuristically pre-validate the container magic before decode\nif !bytes.Contains(data[:12], []byte(\"ftyp\")) {\n\treturn fmt.Errorf(\"not a HEIF container\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := heif.ImageSize(data); err != nil {\n\tif strings.HasPrefix(err.Error(), \"decode HEIF image:\") {\n\t\t// decoder panicked on this input; treat as corrupt, never retry blindly\n\t\treturn fmt.Errorf(\"corrupt HEIF asset: %v\", err)\n\t}\n}","preventionTips":["Never feed untrusted/truncated HEIF bytes directly; the package recovers panics but the asset is still bad","Sanitize imported assets (re-encode via a trusted tool)","Keep goheic updated to reduce panic-triggering decoder bugs"],"tags":["heif","panic-recovery","decoding"],"backgroundTag":"unexpected-response-shape","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}