Go / Gin

How to Fix "cannot use type X as type Y in assignment" in Go Interfaces

4 min read by DebuggedIt

Quick answer

The Go compiler refuses to let you assign a struct to an interface variable or pass it to a function expecting that interface, even though you're sure your...

The Go compiler refuses to let you assign a struct to an interface variable or pass it to a function expecting that interface, even though you're sure your type implements it. This is almost always a method set mismatch β€” either a missing method or a pointer-vs-value receiver conflict.

The Problem

The compile error names both types explicitly and usually lists exactly what's missing:

$ go build .
./main.go:22:14: cannot use user (variable of type User) as Notifier value in argument to SendAlert: User does not implement Notifier (method Notify has pointer receiver)

Or, when a method is missing entirely rather than mismatched:

$ go build .
./main.go:18:20: cannot use &svc (variable of type *EmailService) as type Notifier in variable declaration:
	*EmailService does not implement Notifier (missing method Notify)

Why It Happens

Go interfaces are satisfied implicitly, based purely on method sets β€” there's no implements keyword, so mismatches only surface at compile time when you try to actually use the type as that interface. This error comes from one of two related causes:

  • A method is genuinely missing. Your struct doesn't define every method the interface requires, or a method's signature (parameter types, return types, number of arguments) doesn't exactly match what the interface declares.
  • Pointer vs. value receiver mismatch. If a method is defined with a pointer receiver (func (s *Service) Notify()), only *Service satisfies the interface β€” the value type Service does not, because Go can't guarantee it can call a pointer-receiver method on a value it doesn't have the address of in every context.

This second case is the most common source of confusion, since it's easy to assume a value and its pointer are interchangeable for interface satisfaction β€” in Go, they aren't.

The Fix

First, confirm exactly what the interface requires:

type Notifier interface {
    Notify(message string) error
}

If the error says a method is missing, add it with a matching signature β€” parameter types and return types both have to match exactly, not just be "close enough":

func (s *EmailService) Notify(message string) error {
    return sendEmail(message)
}

If the error is about a pointer receiver, the fix is usually to pass a pointer to the interface-accepting code instead of a value:

svc := EmailService{}
var n Notifier = &svc // use a pointer, not the value directly
SendAlert(n)

If you need the value type itself to satisfy the interface β€” for example, because you're storing it by value in a slice and want to pass elements directly β€” switch the method to a value receiver instead, as long as the method doesn't need to mutate the struct:

func (s EmailService) Notify(message string) error {
    return sendEmail(message)
}

Be aware this changes behavior if the method was relying on mutating the receiver β€” a value receiver operates on a copy, so any field changes inside the method won't persist back to the original struct.

To check which methods a type actually satisfies before you hit the compiler error, you can assert it against the interface directly in a throwaway variable, which gives a clearer compile-time check while you're debugging:

var _ Notifier = (*EmailService)(nil) // compile-time check only, no runtime cost

This line does nothing at runtime, but if *EmailService doesn't fully implement Notifier, the build fails right here with a clear message instead of somewhere else in the code that's harder to trace back.

Still Not Working?

If method signatures look identical but the error persists, check for a subtle type mismatch in the parameters or return values β€” a common trap is one side using a named type and the other using its underlying type, which Go treats as genuinely different:

type Message string

// Interface expects:
Notify(msg Message) error

// But your method has:
func (s *EmailService) Notify(msg string) error { ... } // string != Message, mismatch

Align the exact types on both sides, including custom named types, generic type parameters, and variadic vs. slice parameters β€” Go's interface satisfaction check is strict and exact, with no implicit conversions applied.