gohugoio/hugo · critical
content source: failed to convert %T to string
Error message
content source: failed to convert %T to string: %s
What it means
This is NOT a returned error but a PANIC: Source.ValueAsString calls cast.ToStringE on the content Value and panics with this message if conversion fails. It is triggered when a content source value is a type spf13/cast cannot stringify (e.g. a struct, map, or complex number). Because it panics, an unrecovered occurrence crashes the build.
Solutions
- Always set Source.Value to a string, []byte, or an io.ReadSeeker for content, never a nested struct/map.
- Marshal complex data to a string (e.g. json.Marshal) before assigning it to Source.Value.
- If consuming Source, wrap the call in a recover() guard to convert the panic into a logged error.
Example fix
// before
src := pagemeta.Source{Value: someStruct}
// after
b, _ := json.Marshal(someStruct)
src := pagemeta.Source{Value: string(b)} Defensive patterns
Strategy: validation
Validate before calling
switch s.Value.(type) {
case nil, string, []byte:
// safe
cinstance:
// marshal to string before ValueAsString
} Type guard
func isStringableContent(v any) bool {
switch v.(type) {
case nil, string, []byte, fmt.Stringer:
return true
}
return false
} Try / catch
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("content value not stringable: %v", r)
}
}()
str := src.ValueAsString() Prevention
- Set Source.Value to string, []byte, or an io.Reader only.
- Marshal structs/maps to JSON/YAML strings before assigning to Source.Value.
- Wrap ValueAsString callers in recover() to avoid build crashes.
When it happens
Trigger: A content adapter or Source.Value is set to a non-stringifiable Go value (struct, map[any]any with nested objects, big.Float, etc.) and code later calls ValueAsString/ValueAsOpenReadSeekCloser to read the content.
Common situations: Content adapters passing raw decoded JSON/YAML nested structures straight into Source.Value instead of a string/[]byte/io.Reader. Surfaces as a build crash rather than a graceful error.
Related errors
- failed to decode page map
- argument must be a slice
- called apply using as type
- can't iterate over
- cannot convert type %T to Pages
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/8ad237e562533764.
Report an issue: GitHub.
Appendix: source
Thrown at resources/page/pagemeta/page_frontmatter.go:560
Value any
}
func (s Source) IsZero() bool {
return !hreflect.IsTruthful(s.Value)
}
func (s Source) IsResourceValue() bool {
_, ok := s.Value.(resource.Resource)
return ok
}
func (s Source) ValueAsString() string {
if s.Value == nil {
return ""
}
ss, err := cast.ToStringE(s.Value)
if err != nil {
panic(fmt.Errorf("content source: failed to convert %T to string: %s", s.Value, err))
}
return ss
}
func (s Source) ValueAsOpenReadSeekCloser() hugio.OpenReadSeekCloser {
content := s.ValueAsString()
return func() (hugio.ReadSeekCloser, error) {
return hugio.NewReadSeekerNoOpCloserFromString(content), nil
}
}
// FrontMatterOnlyValues holds values that can only be set via front matter.
type FrontMatterOnlyValues struct {
ResourcesMeta []map[string]any
}
// FrontMatterHandler maps front matter into Page fields and .Params.
// Note that we currently have only extracted the date logic.View on GitHub (pinned to 52c9bd7908)