Fixing the 'type T does not satisfy comparable' Error in Go

intermediate🔷 Go2026-07-27| Go 1.18 or later (Linux, macOS, Windows)

Error Message

invalid operation: cannot compare ... (type T does not satisfy comparable)
#go#generics#comparable#golang-tips

The Refactor That FailedYou’re finally upgrading a legacy Go service to use generics. You decide to start small with a utility function that checks if a slice contains a specific value. The logic is simple, so you write this:

func Contains[T any](slice []T, target T) bool {
    for _, v := range slice {
        if v == target {
            return true
        }
    }
    return false
}

You run go build, expecting a success message. Instead, the compiler blocks you with a frustrating error:

./main.go:10:10: invalid operation: v == target (type T does not satisfy comparable)

Why Go is Blocking Your BuildThe any keyword is an alias for interface{}. It is a common mistake to assume any means 'supports all operations.' In reality, Go’s compiler is incredibly protective. It won't let you use the equality operator (==) unless it can guarantee the type supports it.

Not every type in Go is comparable. Slices, maps, and functions are the primary offenders. If you passed a slice of slices into the function above, the expression v == target would trigger a runtime panic. To prevent this, Go requires you to be explicit about your requirements for T.

The Quick Fix: The 'comparable' ConstraintThe fastest solution is to swap any for the built-in comparable constraint. This constraint limits T to types that work with == and !=. This includes booleans, numbers, strings, pointers, and channels. It also includes structs, provided all their fields are also comparable.

The Corrected Code```

// Swap [T any] for [T comparable] func Contains[T comparable](slice []T, target T) bool { for _, v := range slice { if v == target { return true } } return false }


Now the compiler is happy. If you try to pass `[]int`, it works. If you try to pass `[][]string`, the compiler will catch the mistake at build time rather than letting your app crash in production.
## Handling Non-Comparable TypesWhat if you need to compare complex data? If your struct contains a slice or a map, the `comparable` constraint won't work. In these cases, you should follow the pattern established in Go 1.21’s `slices` package: pass a comparison function.
### Example: Using a Comparison Function```
func ContainsFunc[T any](slice []T, target T, equals func(T, T) bool) bool {
    for _, v := range slice {
        if equals(v, target) {
            return true
        }
    }
    return false
}

// Usage with a non-comparable struct
type User struct {
    ID    int
    Tags  []string // Slices make this struct non-comparable
}

users := []User{{ID: 1, Tags: []string{"admin"}}, {ID: 2}}
target := User{ID: 1}

found := ContainsFunc(users, target, func(a, b User) bool {
    return a.ID == b.ID
})

Verification and TestingFollow these steps to ensure your fix is robust:

  • Verify the Signature: Check that your generic parameter is [T comparable].- Run Your Suite: Execute go test ./.... If it compiles, your types satisfy the constraint.- Test the Bounds: Try passing a slice of maps ([]map[string]string) to the function. You should see a clear compiler error. This confirms the constraint is doing its job.## SummaryThe type T does not satisfy comparable error is just Go's way of asking for a type safety guarantee. Use comparable for simple types like strings or integers. For complex types like slices or maps, skip the equality operator and use a custom comparison function instead.

Related Error Notes