kataras/iris · error

HandleError input argument must be a type of func(iris.Conte

Error message

HandleError input argument must be a type of func(iris.Context, int, error) but got: %T

What it means

macro/handler.CanMakeHandler panics when a macro template parameter's HandleError field is set but is not of the required ParamErrorHandler type, func(iris.Context, int, error) (macro/handler/handler.go:50). The type check happens before the handler is ever used, so a wrong function signature fails immediately at route/filter creation.

Source

Thrown at macro/handler/handler.go:50

// then it returns false.
func CanMakeHandler(tmpl macro.Template) (needsMacroHandler bool) {
	if len(tmpl.Params) == 0 {
		return
	}

	// check if we have params like: {name:string} or {name} or {anything:path} without else keyword or any functions used inside these params.
	// 1. if we don't have, then we don't need to add a handler before the main route's handler (as I said, no performance if macro is not really used)
	// 2. if we don't have any named params then we don't need a handler too.
	for i := range tmpl.Params {
		p := tmpl.Params[i]
		if p.CanEval() {
			// if at least one needs it, then create the handler.
			needsMacroHandler = true

			if p.HandleError != nil {
				// Check for its type.
				if _, ok := p.HandleError.(ParamErrorHandler); !ok {
					panic(fmt.Sprintf("HandleError input argument must be a type of func(iris.Context, int, error) but got: %T", p.HandleError))
				}
			}
			break
		}
	}

	return
}

// MakeHandler creates and returns a handler from a macro template, the handler evaluates each of the parameters if necessary at all.
// If the template does not contain any dynamic attributes and a special handler is NOT required
// then it returns a nil handler.
func MakeHandler(tmpl macro.Template) context.Handler {
	filter := MakeFilter(tmpl)

	return func(ctx *context.Context) {
		if !filter(ctx) {
			if ctx.GetCurrentRoute().StatusErrorCode() == ctx.GetStatusCode() {

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Change HandleError to exactly the signature func(ctx iris.Context, paramIndex int, err error).
  2. If extra context is needed, capture it in a closure: func(ctx iris.Context, i int, err error) { ... } wrapping your logic.
  3. Remove the HandleError field if custom param-error handling is not required.

Example fix

// before
HandleError: func(ctx iris.Context, err error) { ... }

// after
HandleError: func(ctx iris.Context, paramIndex int, err error) { ... }
Defensive patterns

Strategy: type-guard

Validate before calling

// Verify the signature before assigning
var he interface{} = myHandler
if _, ok := he.(macro.ParamErrorHandler); !ok {
    panic("HandleError must be func(iris.Context, int, error)")
}

Type guard

func validParamErrorHandler(f interface{}) bool {
    _, ok := f.(func(iris.Context, int, error))
    return ok
}

Try / catch

defer func() {
    if r := recover(); r != nil {
        log.Fatalf("invalid macro HandleError: %v", r)
    }
}()

Prevention

When it happens

Trigger: Assigning a function with any signature other than func(iris.Context, int, error) to macro/param HandleError, then calling MakeFilter (or TestCanMakeHandler) which invokes CanMakeHandler.

Common situations: Developers write HandleError: func(ctx iris.Context, err error) forgetting the int (parameter index) argument, or pass a custom error handler wrapped in a struct.

Related errors


AI-assisted analysis of kataras/iris@7bedaf55a0 (2026-08-30). Data as JSON: /api/errors/fe9958b12f12084a. Report an issue: GitHub.