gohugoio/hugo · error

failed to decode options: %s

Error message

failed to decode options: %s

What it means

Thrown by images.Dither when mapstructure.WeakDecode fails to decode the options argument into the dither options struct (filters.go:217-220). This happens when the options map contains fields of incompatible types that cannot be weakly coerced.

Source

Thrown at resources/images/filters.go:219

}

// Dither creates a filter that dithers an image.
func (*Filters) Dither(options ...any) gift.Filter {
	ditherOptions := struct {
		Colors     []any
		Method     string
		Serpentine bool
		Strength   float32
	}{
		Method:     "floydsteinberg",
		Serpentine: true,
		Strength:   1.0,
	}

	if len(options) != 0 {
		err := mapstructure.WeakDecode(options[0], &ditherOptions)
		if err != nil {
			panic(fmt.Sprintf("failed to decode options: %s", err))
		}
	}

	if len(ditherOptions.Colors) == 0 {
		ditherOptions.Colors = []any{"000000ff", "ffffffff"}
	}

	if len(ditherOptions.Colors) < 2 {
		panic("palette must have at least two colors")
	}

	var palette []color.Color
	for _, c := range ditherOptions.Colors {
		cc, ok, err := toColorGo(c)
		if !ok || err != nil {
			panic(fmt.Sprintf("%q is an invalid color: specify RGB or RGBA using hexadecimal notation", c))
		}
		palette = append(palette, cc)

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Provide a flat map with keys Colors ([]string), Method (string), Serpentine (bool), Strength (float).
  2. Ensure Colors is always a list even with one entry.
  3. Remove unrecognized/struct-valued keys.

Example fix

// before
{{ $filters = $filters | append (images.Dither (dict "Colors" "000000ff")) }}
// after
{{ $filters = $filters | append (images.Dither (dict "Colors" (slice "000000ff" "ffffffff"))) }}
Defensive patterns

Strategy: validation

Validate before calling

{{ $opts := .opts }}
{{ if and (isset $opts "Colors") (not (reflect.IsSlice (index $opts "Colors"))) }}
  {{ errorf "Dither Colors must be a slice" }}
{{ end }}

Prevention

When it happens

Trigger: Passing a Dither options map where Colors is not a list, Method/Serpentine/Strength are the wrong scalar types, or unknown nested structures. WeakDecode tolerates numeric/string coercion but rejects structural mismatches.

Common situations: Passing Colors as a single string instead of a slice; passing Strength as a map; or passing a struct where a map is expected.

Understand the failure class

Related errors


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