{"record":{"id":"d220d304a98b6e0a","repo":"gohugoio/hugo","slug":"non-comparable-type-s-v","errorCode":null,"errorMessage":"non-comparable type %s: %v","messagePattern":"non-comparable type (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/internal/go_templates/texttemplate/funcs.go","lineNumber":505,"sourceCode":"\t\t\tcase complexKind:\n\t\t\t\ttruth = arg1.Complex() == arg.Complex()\n\t\t\tcase floatKind:\n\t\t\t\ttruth = arg1.Float() == arg.Float()\n\t\t\tcase intKind:\n\t\t\t\ttruth = arg1.Int() == arg.Int()\n\t\t\tcase stringKind:\n\t\t\t\ttruth = arg1.String() == arg.String()\n\t\t\tcase uintKind:\n\t\t\t\ttruth = arg1.Uint() == arg.Uint()\n\t\t\tdefault:\n\t\t\t\tif !canCompare(arg1, arg) {\n\t\t\t\t\treturn false, fmt.Errorf(\"non-comparable types %s: %v, %s: %v\", arg1, arg1.Type(), arg.Type(), arg)\n\t\t\t\t}\n\t\t\t\tif isNil(arg1) || isNil(arg) {\n\t\t\t\t\ttruth = isNil(arg) == isNil(arg1)\n\t\t\t\t} else {\n\t\t\t\t\tif !arg.Type().Comparable() {\n\t\t\t\t\t\treturn false, fmt.Errorf(\"non-comparable type %s: %v\", arg, arg.Type())\n\t\t\t\t\t}\n\t\t\t\t\ttruth = arg1.Interface() == arg.Interface()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif truth {\n\t\t\treturn true, nil\n\t\t}\n\t}\n\treturn false, nil\n}\n\n// ne evaluates the comparison a != b.\nfunc ne(arg1, arg2 reflect.Value) (bool, error) {\n\t// != is the inverse of ==.\n\tequal, err := eq(arg1, arg2)\n\treturn !equal, err\n}","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/internal/go_templates/texttemplate/funcs.go#L487-L523","documentation":"Raised by `eq` when operands are the same non-basic kind, both non-nil, `canCompare` is true, but the operand's type is not reflect.Comparable (funcs.go:503-505). Go does not permit `==` on slices, maps, or funcs, so the template engine refuses too. Format: `val type`.","triggerScenarios":"`{{eq .List .Other}}` where both are `[]string`; `{{eq .Map .OtherMap}}`; comparing two function values.","commonSituations":"Expecting value equality on slices/maps (Go only allows nil-check); comparing pagination slices; deep-equality assumptions from other languages.","solutions":["Compare element-wise via a helper or `reflect.DeepEqual` exposed as a FuncMap entry.","Compare lengths or a representative element instead of the whole container.","Use `{{eq (printf \"%v\" .A) (printf \"%v\" .B)}}` only for diagnostics, not production equality."],"exampleFix":"// before\n{{eq .Tags .PrevTags}}   // both []string\n\n// after\n{{deepEqual .Tags .PrevTags}}   // custom FuncMap using reflect.DeepEqual","handlingStrategy":"fallback","validationCode":"// Use a deep-equal helper instead of eq for slices/maps:\n//   {{deepEqual .Tags .PrevTags}}   // FuncMap: reflect.DeepEqual","typeGuard":"func isComparable(v interface{}) bool {\n    if v == nil { return false }\n    t := reflect.TypeOf(v)\n    return t.Comparable()\n}","tryCatchPattern":null,"preventionTips":["Never use eq on slices, maps, or funcs — Go forbids it.","Expose reflect.DeepEqual as a FuncMap entry for structural equality.","Compare lengths or canonicalized forms as a lighter alternative."],"tags":["template","comparison","eq","non-comparable","text-template"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}