gohugoio/hugo · error

invalid font source: %s

Error message

invalid font source: %s

What it means

Thrown by images.Text when the `font` option resolves to a value that implements the `error` interface (filters.go:115-117). This indicates the font resource itself failed to load/resolve and the error object was passed through instead of a usable font source, so the filter refuses to proceed.

Source

Thrown at resources/images/filters.go:116

				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.
				// Replace it with a string in the map used as basis for the
				// hash string.
				opt["font"] = identifier.Key()

			}
		}
	}

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Check the font resource for an error before passing it to images.Text.
  2. Verify the font file exists under assets/ and the path used in resources.Get is correct.
  3. If fetching remotely, confirm the URL returns 200 and a valid font before forwarding it.

Example fix

// before
{{ $f := resources.GetRemote "https://example.com/font.woff" }}
{{ $filters = $filters | append (images.Text "Hi" (dict "font" $f)) }}
// after
{{ $f := resources.GetRemote "https://example.com/font.woff" }}
{{ if $f.Err }}{{ errorf "font load failed: %v" $f.Err }}{{ end }}
{{ $filters = $filters | append (images.Text "Hi" (dict "font" $f)) }}
Defensive patterns

Strategy: validation

Validate before calling

{{ $f := resources.GetRemote "https://example.com/font.woff" }}
{{ with $f.Err }}
  {{ errorf "font fetch failed: %v" . }}
{{ end }}

Type guard

// AsError reports whether v carries a load error (implements error).
func AsError(v any) bool { _, ok := v.(error); return ok }

Prevention

When it happens

Trigger: Passing a resource lookup that returned an error (e.g. a failed resources.Get or a malformed resources.GetRemote result) directly as the `font` argument. The type switch detects the error type first and panics with the underlying error message.

Common situations: Font file is missing from assets/, the path is wrong, GetRemote returned a non-200 response whose error is forwarded, or a resources.Concat/FromString produced an error that was not checked before being handed to Text.

Related errors


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