Skip to content

Fix: Go cannot use X (type Y) as type Z in argument

FixDevs ·

Quick Answer

How to fix Go 'cannot use as type' error caused by type mismatches, interface satisfaction, pointer vs value receivers, type conversions, and generic constraints.

The Error

You compile Go code and get:

cannot use myVar (variable of type string) as int value in argument to processNumber

Or variations:

cannot use &myStruct (value of type *MyStruct) as MyInterface value in variable declaration:
*MyStruct does not implement MyInterface (missing method DoSomething)
cannot use mySlice (variable of type []int) as []interface{} value in argument
cannot use 42 (untyped int constant) as string value in return statement
cannot use myFunc (value of type func(int)) as func(interface{}) value

Go’s type system is strict. You passed a value of one type where a different type is expected, and Go does not implicitly convert between them.

Why This Happens

Go has no implicit type conversions. Unlike JavaScript or Python, Go does not automatically convert an int to a string, a []int to []interface{}, or a float64 to an int. You must convert explicitly.

Additionally, Go interfaces are satisfied structurally (no explicit implements keyword), but the satisfaction rules are strict about pointer vs value receivers.

Common causes:

  • Wrong argument type. Passing a string where an int is expected.
  • Missing interface method. A type does not implement all methods of an interface.
  • Pointer vs value receiver mismatch. A method is defined on *T but you pass T (not a pointer).
  • Slice type mismatch. []int is not []interface{} even though int satisfies interface{}.
  • Named type vs underlying type. type MyInt int is a different type from int.

Fix 1: Use Explicit Type Conversion

Go requires explicit conversions between compatible types:

var x int = 42
var y float64 = float64(x)   // int → float64
var z string = strconv.Itoa(x)  // int → string (not string(x)!)

var f float64 = 3.14
var i int = int(f)   // float64 → int (truncates decimal)

var s string = "hello"
var b []byte = []byte(s)  // string → []byte
var s2 string = string(b)  // []byte → string

Common mistake — string(int):

s := string(65)     // "A" — converts int to Unicode codepoint, NOT "65"!
s := strconv.Itoa(65)  // "65" — converts int to its string representation

Pro Tip: Use strconv for numeric ↔ string conversions. string(n) interprets n as a Unicode codepoint, which is almost never what you want. strconv.Itoa(n) converts the number to its decimal string representation.

Fix 2: Fix Interface Satisfaction

If the error says a type does not implement an interface:

type Writer interface {
    Write(data []byte) (int, error)
}

type MyWriter struct{}

func (w MyWriter) Write(data string) error {  // Wrong signature!
    return nil
}

var w Writer = MyWriter{}
// cannot use MyWriter{} as Writer value: MyWriter does not implement Writer
// (wrong type for method Write)

The method signature must exactly match the interface method:

func (w MyWriter) Write(data []byte) (int, error) {
    fmt.Print(string(data))
    return len(data), nil
}

Parameter types, return types, and the number of parameters must all match exactly.

Fix 3: Fix Pointer vs Value Receiver

Methods defined on *T (pointer receiver) are only available to pointer values when satisfying interfaces:

Broken:

type Stringer interface {
    String() string
}

type User struct {
    Name string
}

func (u *User) String() string {  // Pointer receiver
    return u.Name
}

var s Stringer = User{Name: "Alice"}  // ERROR!
// cannot use User{} as Stringer value: User does not implement Stringer
// (method String has pointer receiver)

Fixed — use a pointer:

var s Stringer = &User{Name: "Alice"}  // Pointer — works!

Or use a value receiver:

func (u User) String() string {  // Value receiver
    return u.Name
}

var s Stringer = User{Name: "Alice"}  // Works — value receiver
var s Stringer = &User{Name: "Alice"} // Also works — pointer can use value receivers

Rule of thumb:

ReceiverValue satisfies interface?Pointer satisfies interface?
func (t T)YesYes
func (t *T)NoYes

Common Mistake: Defining methods with pointer receivers but trying to store values (not pointers) in interface variables. If any method uses a pointer receiver, you must use a pointer to satisfy the interface. Consistency helps — use either all pointer receivers or all value receivers for a type.

Fix 4: Fix Slice Type Mismatches

Go slices are not covariant. []int is not []interface{} even though int satisfies interface{}:

Broken:

func printAll(items []interface{}) {
    for _, item := range items {
        fmt.Println(item)
    }
}

numbers := []int{1, 2, 3}
printAll(numbers)
// cannot use numbers (variable of type []int) as []interface{} value

Fixed — use generics (Go 1.18+):

func printAll[T any](items []T) {
    for _, item := range items {
        fmt.Println(item)
    }
}

numbers := []int{1, 2, 3}
printAll(numbers)  // Works!

Fixed — convert manually:

numbers := []int{1, 2, 3}
items := make([]interface{}, len(numbers))
for i, n := range numbers {
    items[i] = n
}
printAll(items)

Why this limitation exists: In Go, []int and []interface{} have different memory layouts. An int is stored directly in the slice element; an interface{} stores a type descriptor and a pointer. Go cannot reinterpret the memory, so an explicit conversion is required.

Fix 5: Fix Named Type Conversions

Named types are distinct from their underlying types:

type UserID int
type OrderID int

func processUser(id UserID) {}

var orderID OrderID = 42
processUser(orderID)
// cannot use orderID (variable of type OrderID) as UserID value

Fix: Convert explicitly:

processUser(UserID(orderID))

Named types with the same underlying type can be converted between each other, but Go does not do it implicitly. This is a feature — it prevents mixing up IDs of different entity types.

Fix 6: Fix Function Type Mismatches

Function types must match exactly:

type Handler func(w http.ResponseWriter, r *http.Request)

func myHandler(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("Hello"))
}

var h Handler = myHandler  // Works — exact match

// But:
type GenericHandler func(interface{})

func specificHandler(s string) {}

var g GenericHandler = specificHandler
// cannot use specificHandler as GenericHandler value

Fix with adapters:

var g GenericHandler = func(v interface{}) {
    specificHandler(v.(string))
}

Fix 7: Fix Map Type Mismatches

Like slices, maps are not covariant:

func process(m map[string]interface{}) {}

data := map[string]int{"a": 1, "b": 2}
process(data)
// cannot use data as map[string]interface{} value

Fixed — use generics:

func process[V any](m map[string]V) {}

data := map[string]int{"a": 1, "b": 2}
process(data)  // Works!

Fixed — convert manually:

converted := make(map[string]interface{}, len(data))
for k, v := range data {
    converted[k] = v
}
process(converted)

Fix 8: Fix Error Interface Returns

A common confusion with the error interface:

type MyError struct {
    Message string
}

func (e *MyError) Error() string {
    return e.Message
}

func doSomething() error {
    var err *MyError = nil
    return err  // Returns a non-nil interface containing a nil pointer!
}

if err := doSomething(); err != nil {
    // This is TRUE even though the underlying pointer is nil!
    fmt.Println("Error:", err)
}

Fixed — return nil directly:

func doSomething() error {
    // ...
    return nil  // Return nil, not a typed nil pointer
}

This is a notorious Go gotcha. An interface is only nil when both its type and value are nil. A nil *MyError stored in an error interface has a non-nil type, so err != nil is true.

For related Go issues with unused variables, see Fix: Go declared and not used.

Still Not Working?

Check for generic constraints. In Go 1.18+, generic type parameters must satisfy their constraints:

func sum[T int | float64](values []T) T { ... }

sum([]string{"a", "b"})  // string does not satisfy int | float64

Check for type assertions. If you need to work with interface{} values, use type assertions:

var v interface{} = "hello"
s := v.(string)   // Type assertion — panics if wrong type
s, ok := v.(string)  // Safe assertion — ok is false if wrong type

Check for struct embedding. Embedded structs can satisfy interfaces through promoted methods, but only if the method signatures match exactly.

Use the compiler’s suggestion. Go’s error messages often include the expected and actual types. Compare them carefully — the difference might be subtle (pointer vs value, named vs unnamed type, different package paths for the same type name).

For Go module issues that prevent compilation, see Fix: Go module not found.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles