gohugoio/hugo · error
non-comparable types %s: %v, %s: %v
Error message
non-comparable types %s: %v, %s: %v
What it means
Raised by `eq` when two operands share the same `basicKind` invalidKind fallback (i.e. neither is a basic scalar kind), they are not nil, and `canCompare` is false (funcs.go:498-499). This catches comparisons between struct/interface/pointer values of different dynamic types that the engine cannot equate. Format: `val1 type1 type2 val2`.
Source
Thrown at tpl/internal/go_templates/texttemplate/funcs.go:499
}
}
} else {
switch k1 {
case boolKind:
truth = arg1.Bool() == arg.Bool()
case complexKind:
truth = arg1.Complex() == arg.Complex()
case floatKind:
truth = arg1.Float() == arg.Float()
case intKind:
truth = arg1.Int() == arg.Int()
case stringKind:
truth = arg1.String() == arg.String()
case uintKind:
truth = arg1.Uint() == arg.Uint()
default:
if !canCompare(arg1, arg) {
return false, fmt.Errorf("non-comparable types %s: %v, %s: %v", arg1, arg1.Type(), arg.Type(), arg)
}
if isNil(arg1) || isNil(arg) {
truth = isNil(arg) == isNil(arg1)
} else {
if !arg.Type().Comparable() {
return false, fmt.Errorf("non-comparable type %s: %v", arg, arg.Type())
}
truth = arg1.Interface() == arg.Interface()
}
}
}
if truth {
return true, nil
}
}
return false, nil
}
View on GitHub (pinned to 52c9bd7908)
Solutions
- Compare a stable identifier instead of whole objects: `{{eq .A.ID .B.ID}}`.
- Ensure both operands are the same concrete type before comparing.
- Implement an explicit equality helper FuncMap entry and call that.
Example fix
// before
{{eq .Author .Editor}} // *User vs *Editor
// after
{{eq .Author.ID .Editor.ID}} Defensive patterns
Strategy: type-guard
Validate before calling
// Compare identifiers, not whole objects of different types:
// {{eq .Author.ID .Editor.ID}} Type guard
func sameConcreteType(a, b interface{}) bool {
if a == nil || b == nil { return false }
return reflect.TypeOf(a) == reflect.TypeOf(b)
} Prevention
- Compare a stable ID rather than heterogeneous structs.
- Ensure both operands share a concrete type before eq.
- Expose a typed equality helper for complex types.
When it happens
Trigger: `{{eq .A .B}}` where `.A` is a `*User` and `.B` is a `*Post`; comparing two struct values of different types; comparing a struct to a map.
Common situations: Comparing object references of different concrete types; refactoring types so two values that used to be comparable no longer are; loose equality expectations across heterogeneous data.
Related errors
- incompatible types for comparison: %v and %v
- non-comparable type %s: %v
- can't index item of type %s
- can't slice item of type %s
- len of type %s
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/0b12e33bd4b1e30b.
Report an issue: GitHub.