gohugoio/hugo · error
exif init failed: %s
Error message
exif init failed: %s
What it means
Panic in imageResource.Exif() when the lazily-initialized exifInfoFn() returns an error. Hugo decodes EXIF metadata from the image (via Imaging.DecodeExif) and caches it; if decoding fails (corrupt EXIF, unsupported format, cache I/O error), the error is propagated as a panic from Exif(). The error string from the underlying failure is included.
Source
Thrown at resources/image.go:185
func (i *imageResource) newColorsFn() func() ([]images.Color, error) {
return sync.OnceValues(func() ([]images.Color, error) {
img, err := i.DecodeImage()
if err != nil {
return nil, err
}
colors := color_extractor.ExtractColors(img)
result := make([]images.Color, len(colors))
for j, c := range colors {
result[j] = images.ColorGoToColor(c)
}
return result, nil
})
}
func (i *imageResource) Exif() *meta.ExifInfo {
x, err := i.root.exifInfoFn()
if err != nil {
panic(fmt.Sprintf("exif init failed: %s", err))
}
return x
}
func (i *imageResource) Meta() *meta.MetaInfo {
m, err := i.root.metaInfoFn()
if err != nil {
panic(fmt.Sprintf("meta init failed: %s", err))
}
return m
}
func (i *imageResource) getImageMetaInfoCacheTargetPath() string {
// Increment to invalidate the meta cache
const imageMetaInfoVersionNumber = 1
cfgHash := i.getSpec().Imaging.Cfg.SourceHash
df := i.getResourcePaths()View on GitHub (pinned to 52c9bd7908)
Solutions
- Validate the image file is a valid JPEG/TIFF with readable EXIF before calling .Exif.
- Check filesystem permissions on the Hugo cache directory (often resources/_gen).
- Re-export/repair the source image's EXIF, or strip EXIF if you do not need it.
- Guard template usage: {{ with .Exif }}...{{ end }} will still panic; instead pre-validate the resource or wrap usage in a partial that checks the image format.
Example fix
{{/* before: .Exif panics on a corrupt image */}}
{{ with $img.Exif }}{{ .Date }}{{ end }}
{{/* after: only call Exif for known photo formats; repair the source */}}
{{ if in (slice "jpg" "jpeg" "tiff") $img.MediaType.SubType }}
{{ with $img.Exif }}{{ .Date }}{{ end }}
{{ end }} Defensive patterns
Strategy: validation
Validate before calling
// Validate the image is a photo format with readable EXIF before calling .Exif.
// Template side: gate on media type.
// Go side: decode a probe to ensure the file is a valid JPEG/TIFF.
func hasExif(subType string) bool {
switch subType {
case "jpeg", "jpg", "tiff":
return true
}
return false
} Try / catch
// Exif panics on decode failure; recover to degrade gracefully:
func safeExif(img *resources.ImageResource) (exif *meta.ExifInfo, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("exif decode failed: %v", r)
}
}()
return img.Exif(), nil
} Prevention
- Only call .Exif on JPEG/TIFF resources.
- Keep the cache directory writable.
- Repair/strip EXIF on corrupt source images.
- Validate uploads before they enter assets/.
When it happens
Trigger: Calling .Exif on an image resource whose EXIF data is corrupt or unsupported by the decoder, or when the image file cache cannot be read/written. Passing a non-photographic image (SVG, some PNGs) where EXIF decoding fails. Permissions issues on the cache directory.
Common situations: A corrupt or truncated JPEG/TIFF uploaded to assets/images. A misconfigured imaging.exif config. Read-only cache filesystem. An image format the EXIF library cannot parse.
Related errors
- meta init failed: %s
- resource %d to post process is nil
- h.ResourceSpec is nil
- alignx must be one of left, center, right
- config needs a filename
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/e262180ec6f33372.
Report an issue: GitHub.