gohugoio/hugo · error

aligny must be one of top, center, bottom

Error message

aligny must be one of top, center, bottom

What it means

Thrown by the images.Text filter when its `aligny` option is set to a value other than "top", "center", or "bottom". The filter validates vertical text alignment at filter-construction time (filters.go:108-110) and panics to fail fast rather than silently rendering misaligned text. Hugo surfaces this as a build error.

Solutions

  1. Set aligny to one of the literal strings "top", "center", or "bottom".
  2. If you meant CSS middle, use "center".
  3. Ensure the value is lowercase; do not rely on case-insensitivity.

Example fix

// before
{{ $filters = $filters | append (images.Text "Hello" (dict "aligny" "middle")) }}
// after
{{ $filters = $filters | append (images.Text "Hello" (dict "aligny" "center")) }}
Defensive patterns

Strategy: validation

Validate before calling

{{ $aligny := lower (printf "%v" (.aligny | default "top")) }}
{{ if not (in (slice "top" "center" "bottom") $aligny) }}
  {{ errorf "aligny must be top/center/bottom, got %q" $aligny }}
{{ end }}

Type guard

// ValidAligny reports whether v is an accepted vertical alignment.
func ValidAligny(v string) bool {
    switch v {
    case "top", "center", "bottom":
        return true
    }
    return false
}

Prevention

When it happens

Trigger: Calling images.Text with an options map whose `aligny` key holds any string besides top/center/bottom (e.g. "middle", "Top", "baseline"). The comparison is case-sensitive and not lowercased, unlike many other filter options.

Common situations: Developers coming from CSS (where `vertical-align: middle` is valid) write `aligny "middle"`; or they capitalize the value. Copying alignx/aligny values from a design tool that emits different vocabulary also triggers it.

Related errors


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

Appendix: source

Thrown at resources/images/filters.go:109

			case "color":
				if color, ok, _ := toColorGo(v); ok {
					tf.color = color
				}
			case "size":
				tf.size = cast.ToFloat64(v)
			case "x":
				tf.x = cast.ToInt(v)
			case "y":
				tf.y = cast.ToInt(v)
			case "alignx":
				tf.alignx = cast.ToString(v)
				if tf.alignx != "left" && tf.alignx != "center" && tf.alignx != "right" {
					panic("alignx must be one of left, center, right")
				}
			case "aligny":
				tf.aligny = cast.ToString(v)
				if tf.aligny != "top" && tf.aligny != "center" && tf.aligny != "bottom" {
					panic("aligny must be one of top, center, bottom")
				}

			case "linespacing":
				tf.linespacing = cast.ToInt(v)
			case "font":
				if err, ok := v.(error); ok {
					panic(fmt.Sprintf("invalid font source: %s", err))
				}
				fontSource, ok1 := v.(hugio.ReadSeekCloserProvider)
				identifier, ok2 := v.(resource.Identifier)

				if !(ok1 && ok2) {
					panic(fmt.Sprintf("invalid text font source: %T", v))
				}

				tf.fontSource = fontSource

				// The input value isn't hashable and will not make a stable key.

View on GitHub (pinned to 52c9bd7908)