golang/go · error

cannot instantiate non-generic %s: has no type parameters

Error message

cannot instantiate non-generic %s: has no type parameters

What it means

The Instantiate function (exported as go/types.Instantiate) creates a concrete type from a generic type by substituting type arguments. When called with validate=true on a type whose TypeParams().list() is empty, this error is returned. The type was recognized as a genericType (Named, Alias, or Signature) but has zero declared type parameters.

Source

Thrown at src/cmd/compile/internal/types2/instantiate.go:66

// for *Signature types, Instantiate will panic immediately if the type argument
// count is incorrect; for *Named types, a panic may occur later inside the
// *Named API.
func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, error) {
	if ctxt == nil {
		ctxt = NewContext()
	}
	orig_, ok := orig.(genericType) // signature of Instantiate must not change for backward-compatibility
	if !ok {
		panic(sprintf(nil, false, "cannot instantiate non-generic %s: expected *Named, *Alias, or *Signature", orig))
	}
	if len(targs) == 0 {
		panic(sprintf(nil, false, "cannot instantiate %s: empty type argument list", orig))
	}

	if validate {
		tparams := orig_.TypeParams().list()
		if len(tparams) == 0 {
			return nil, fmt.Errorf("cannot instantiate non-generic %s: has no type parameters", orig)
		}
		if len(targs) != len(tparams) {
			return nil, fmt.Errorf("cannot instantiate %s: got %d type arguments but have %d type parameters", orig, len(targs), len(tparams))
		}
		if i, err := (*Checker)(nil).verify(nopos, tparams, targs, ctxt); err != nil {
			return nil, &ArgumentError{i, err}
		}
	}

	inst := (*Checker)(nil).instance(nopos, orig_, targs, nil, ctxt)
	return inst, nil
}

// instance instantiates the given original (generic) function or type with the
// provided type arguments and returns the resulting instance. If an identical
// instance exists already in the given contexts, it returns that instance,
// otherwise it creates a new one. If there is an error (such as wrong number
// of type arguments), the result is Typ[Invalid].

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Check TypeParams().Len() > 0 before calling Instantiate
  2. Only call Instantiate on types you have confirmed are generic
  3. Pass validate=false if you do not need validation, but note that panics may occur later for *Named types with wrong argument counts
  4. Cache genericness checks to avoid repeated TypeParams() calls in hot paths

Example fix

// before
inst, err := types.Instantiate(ctxt, someType, targs, true)

// after
if someType.TypeParams().Len() == 0 {
    return someType // not generic, no instantiation needed
}
inst, err := types.Instantiate(ctxt, someType, targs, true)
Defensive patterns

Strategy: type-guard

Validate before calling

// Check if a type is generic before calling Instantiate
import (
    "go/types"
)

func safeInstantiate(ctxt *types.Context, t types.Type, targs []types.Type) (types.Type, error) {
    // Get type parameters from Named, Alias, or Signature
    var tparams *types.TypeParamList
    switch t := t.(type) {
    case *types.Named:
        tparams = t.TypeParams()
    case *types.Alias:
        tparams = t.TypeParams()
    case *types.Signature:
        tparams = t.TypeParams()
    default:
        return t, nil // not instantiable, return as-is
    }
    if tparams == nil || tparams.Len() == 0 {
        return t, nil // not generic, no instantiation needed
    }
    return types.Instantiate(ctxt, t, targs, true)
}

Type guard

// Type guard: returns true if the type has type parameters (is generic)
func isGeneric(t types.Type) bool {
    var tparams *types.TypeParamList
    switch t := t.(type) {
    case *types.Named:
        tparams = t.TypeParams()
    case *types.Alias:
        tparams = t.TypeParams()
    case *types.Signature:
        tparams = t.TypeParams()
    default:
        return false
    }
    return tparams != nil && tparams.Len() > 0
}

Prevention

When it happens

Trigger: Calling types.Instantiate(ctxt, nonGenericType, typeArgs, true) where the original type has no type parameters. For example, instantiating a plain *types.Named for a struct without type parameters, or a *types.Signature for a non-generic function.

Common situations: Dynamic type processing code (e.g., in code generators, serializers, or ORMs) that calls Instantiate on all types without checking if they are generic. Stale type information after refactoring a type from generic to non-generic. Reflection-based tools that enumerate and instantiate types programmatically.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/26b8b9d22190e6df. Report an issue: GitHub.