{"record":{"id":"564938012e9f609d","repo":"apache/answer","slug":"decode-image-error-v","errorCode":null,"errorMessage":"decode image error: %v","messagePattern":"decode image error: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/checker/file_type.go","lineNumber":126,"sourceCode":"\t}\n\treturn nil\n}\n\n// formatSpecificImageCheck fully decodes the image using a format-specific decoder.\nfunc formatSpecificImageCheck(file io.Reader, ext string, _ int) error {\n\tvar err error\n\tswitch ext {\n\tcase \"jpg\", \"jpeg\":\n\t\t_, err = jpeg.Decode(file)\n\tcase \"png\":\n\t\t_, err = png.Decode(file)\n\tcase \"gif\":\n\t\t_, err = gif.Decode(file)\n\tdefault:\n\t\treturn fmt.Errorf(\"unsupported image format: %s\", ext)\n\t}\n\tif err != nil {\n\t\treturn fmt.Errorf(\"decode image error: %v\", err)\n\t}\n\treturn nil\n}\n\nfunc webpImageConfigCheck(file io.Reader, _ string, maxImageMegapixel int) error {\n\tconfig, err := webp.DecodeConfig(file)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"decode webp image config error: %v\", err)\n\t}\n\tif imageSizeTooLarge(config, maxImageMegapixel) {\n\t\treturn fmt.Errorf(\"image size too large\")\n\t}\n\treturn nil\n}\n\nfunc webpImageCheck(file io.Reader, _ string, _ int) error {\n\t_, err := webp.Decode(file)\n\tif err != nil {","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/apache/answer/blob/3b9f1370612e690a0b7f230f05e688930db4c6d3/pkg/checker/file_type.go#L108-L144","documentation":"formatSpecificImageCheck wraps any error from jpeg.Decode, png.Decode, or gif.Decode at pkg/checker/file_type.go:126. Unlike the config check, this fully decodes the pixel data, so it catches corruption deeper in the file: bad color tables, broken IDAT/strips, unexpected EOF mid-scanline, or invalid frame data.","triggerScenarios":"DecodeAndCheckImageFile runs the second-stage full decode on a jpg/jpeg/png/gif whose header parsed fine but whose body is corrupt, truncated, or a header-only forgery.","commonSituations":"Files cut off mid-upload, images re-encoded by broken tools, polyglot files whose headers pass but bodies fail, or bit-rotted files on old storage.","solutions":["Ask the user to re-upload the file; the image body is likely truncated or corrupt","Validate the image server-side or client-side (e.g. ImageMagick identify, browser preview) before persisting it","Check upload pipeline integrity: proxy body-size limits, multipart parsing, storage write completion","Log the wrapped error to distinguish 'unexpected EOF' (truncation) from format-specific corruption"],"exampleFix":"// before: store the raw upload immediately\nos.Rename(tmpPath, finalPath)\n// after: decode fully first (checker does this) and only persist on success\nif checker.DecodeAndCheckImageFile(tmpPath, maxMP) { os.Rename(tmpPath, finalPath) } else { os.Remove(tmpPath); return errors.New(\"invalid image\") }","handlingStrategy":"try-catch","validationCode":"head := make([]byte, 512)\nn, _ := io.ReadFull(f, head)\nif !looksLikeImage(head[:n]) { return errors.New(\"not a real image\") }","typeGuard":"func isFullDecodeErr(err error) bool { return err != nil && strings.HasPrefix(err.Error(), \"decode image error\") }","tryCatchPattern":"ok := checker.DecodeAndCheckImageFile(tmpPath, maxMP)\nif !ok {\n\tos.Remove(tmpPath)\n\treturn errors.New(\"image failed full decode; likely corrupt or truncated\")\n}","preventionTips":["Only persist uploads after full decode succeeds","Compare received byte count against Content-Length to catch truncation","Re-test files after storage migration or proxy changes","Distinguish EOF-type errors (truncation) from structural corruption in logs"],"tags":["go","image-decoding","file-upload","data-integrity"],"backgroundTag":"image-decode-failed","analyzedSha":"3b9f1370612e690a0b7f230f05e688930db4c6d3","analyzedAt":"2026-09-05T18:18:39.533Z","contentChangedAt":"2026-09-05T18:18:39.533Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}