gohugoio/hugo · error

%T is not an image filter

Error message

%T is not an image filter

What it means

Thrown by images.ToFilters when the input is not a filter, a slice of filters, or a single filter wrapper (image.go:492-506). ToFilters is used internally by image processing pipelines to normalize a heterogeneous argument list into []gift.Filter; unrecognized types panic with the concrete Go type (%T).

Source

Thrown at resources/images/image.go:505

	}
	return in
}

// ToFilters converts the given input to a slice of gift.Filter.
func ToFilters(in any) []gift.Filter {
	switch v := in.(type) {
	case []gift.Filter:
		return v
	case []filter:
		vv := make([]gift.Filter, len(v))
		for i, f := range v {
			vv[i] = f
		}
		return vv
	case gift.Filter:
		return []gift.Filter{v}
	default:
		panic(fmt.Sprintf("%T is not an image filter", in))
	}
}

// IsOpaque returns false if the image has alpha channel and there is at least 1
// pixel that is not (fully) opaque.
func IsOpaque(img image.Image) bool {
	if oim, ok := img.(interface {
		Opaque() bool
	}); ok {
		return oim.Opaque()
	}

	return false
}

// ImageSource identifies and decodes an image.
type ImageSource interface {
	DecodeImage() (image.Image, error)

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Ensure every element is produced by an images.* filter constructor (Process, Text, Padding, Dither, etc.).
  2. Do not append raw scalars, resources, or maps to a filter slice.
  3. Inspect the printed type (%T) to find the offending element.

Example fix

// before
{{ $filters := slice }}
{{ $filters = $filters | append "#ffffff" }}
{{ $img := $img.Filter $filters }}
// after
{{ $filters := slice }}
{{ $filters = $filters | append (images.Padding 10 "#ffffff") }}
{{ $img := $img.Filter $filters }}
Defensive patterns

Strategy: type-guard

Validate before calling

{{ range $f := $filters }}
  {{ if not (reflect.IsMap $f) }}{{ end }}
{{ end }}

Type guard

// IsGiftFilter reports whether v can be accepted by images.ToFilters.
func IsGiftFilter(v any) bool {
    switch v.(type) {
    case gift.Filter, []gift.Filter, images.FilterWrapper:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: Passing a non-filter value (string, int, map, arbitrary struct) where a filter is expected — typically via the images.Process filter list or when manually building a filter slice with mixed types.

Common situations: Template builds a filter slice and accidentally appends a plain value (e.g. a color string or a resource) instead of a filter produced by images.* functions.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/b9d4bc3d379a984c. Report an issue: GitHub.