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

  1. Compare a stable identifier instead of whole objects: `{{eq .A.ID .B.ID}}`.
  2. Ensure both operands are the same concrete type before comparing.
  3. 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

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


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