apache/answer · error

decode image error: %v

Error message

decode image error: %v

What it means

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.

Source

Thrown at pkg/checker/file_type.go:126

	}
	return nil
}

// formatSpecificImageCheck fully decodes the image using a format-specific decoder.
func formatSpecificImageCheck(file io.Reader, ext string, _ int) error {
	var err error
	switch ext {
	case "jpg", "jpeg":
		_, err = jpeg.Decode(file)
	case "png":
		_, err = png.Decode(file)
	case "gif":
		_, err = gif.Decode(file)
	default:
		return fmt.Errorf("unsupported image format: %s", ext)
	}
	if err != nil {
		return fmt.Errorf("decode image error: %v", err)
	}
	return nil
}

func webpImageConfigCheck(file io.Reader, _ string, maxImageMegapixel int) error {
	config, err := webp.DecodeConfig(file)
	if err != nil {
		return fmt.Errorf("decode webp image config error: %v", err)
	}
	if imageSizeTooLarge(config, maxImageMegapixel) {
		return fmt.Errorf("image size too large")
	}
	return nil
}

func webpImageCheck(file io.Reader, _ string, _ int) error {
	_, err := webp.Decode(file)
	if err != nil {

View on GitHub (pinned to 3b9f137061)

Solutions

  1. Ask the user to re-upload the file; the image body is likely truncated or corrupt
  2. Validate the image server-side or client-side (e.g. ImageMagick identify, browser preview) before persisting it
  3. Check upload pipeline integrity: proxy body-size limits, multipart parsing, storage write completion
  4. Log the wrapped error to distinguish 'unexpected EOF' (truncation) from format-specific corruption

Example fix

// before: store the raw upload immediately
os.Rename(tmpPath, finalPath)
// after: decode fully first (checker does this) and only persist on success
if checker.DecodeAndCheckImageFile(tmpPath, maxMP) { os.Rename(tmpPath, finalPath) } else { os.Remove(tmpPath); return errors.New("invalid image") }
Defensive patterns

Strategy: try-catch

Validate before calling

head := make([]byte, 512)
n, _ := io.ReadFull(f, head)
if !looksLikeImage(head[:n]) { return errors.New("not a real image") }

Type guard

func isFullDecodeErr(err error) bool { return err != nil && strings.HasPrefix(err.Error(), "decode image error") }

Try / catch

ok := checker.DecodeAndCheckImageFile(tmpPath, maxMP)
if !ok {
	os.Remove(tmpPath)
	return errors.New("image failed full decode; likely corrupt or truncated")
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/answer@3b9f137061 (2026-09-05). Data as JSON: /api/errors/564938012e9f609d. Report an issue: GitHub.