kataras/iris · error

remove handler: unexpected type of %T

Error message

remove handler: unexpected type of %T

What it means

APIBuilder.RemoveHandler accepts only string (handler name) or context.Handler values to identify which middleware/handler to remove. Any other argument type reaches the default branch of the type switch and panics with the offending Go type (%T). It is a compile-time-absent type safety check done at runtime via a type switch.

Source

Thrown at core/router/api_builder.go:1417

// then this is used to set the total amount of removed handlers.
//
// Returns the Party itself for chain calls.
//
// Should be called before children routes regitration.
func (api *APIBuilder) RemoveHandler(namesOrHandlers ...any) Party {
	var counter *int

	for _, nameOrHandler := range namesOrHandlers {
		handlerName := ""
		switch h := nameOrHandler.(type) {
		case string:
			handlerName = h
		case context.Handler: //, func(*context.Context):
			handlerName = context.HandlerName(h)
		case *int:
			counter = h
		default:
			panic(fmt.Sprintf("remove handler: unexpected type of %T", h))
		}

		api.middleware = removeHandler(handlerName, api.middleware, counter)
		api.doneHandlers = removeHandler(handlerName, api.doneHandlers, counter)
	}

	return api
}

// Reset removes all the begin and done handlers that may derived from the parent party via `Use` & `Done`,
// and the execution rules.
// Note that the `Reset` will not reset the handlers that are registered via `UseGlobal` & `DoneGlobal`.
//
// Returns this Party.
func (api *APIBuilder) Reset() Party {
	api.middleware = api.middleware[0:0]
	api.middlewareErrorCode = api.middlewareErrorCode[0:0]
	api.ResetRouterFilters()

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Pass a string handler name or a value of type context.Handler
  2. If using the occurrence counter, pass a *int (e.g. &count), not an int
  3. Convert function literals to context.Handler, e.g. context.Handler(myFunc) or use the named handler registration

Example fix

// before
app.RemoveHandler(func(ctx *iris.Context) { ... }) // panics: unexpected type
// after
app.RemoveHandler(iris.Context.Handler(myHandler)) // or
app.RemoveHandler("myHandlerName")
Defensive patterns

Strategy: type-guard

Validate before calling

func canRemoveHandler(v any) bool {
    switch v.(type) {
    case string, context.Handler:
        return true
    default:
        return false
    }
}

Type guard

func isRemoveHandlerArg(v any) bool {
    switch v.(type) {
    case string:
        return true
    case context.Handler:
        return true
    default:
        return false
    }
}

Try / catch

func removeHandlerSafe(api *iris.APIBuilder, arg any) {
    defer func() {
        if r := recover(); r != nil {
            log.Printf("RemoveHandler panicked: %v (arg %T)", r, arg)
        }
    }()
    if !isRemoveHandlerArg(arg) {
        log.Printf("skip: unsupported arg type %T", arg)
        return
    }
    api.RemoveHandler(arg)
}

Prevention

When it happens

Trigger: Calling Party/APIBuilder RemoveHandler (or RemoveHandler-ish API at api_builder.go) with an unsupported value, e.g. a func(iris.Context) literal (not typed as context.Handler), an int used as counter without *int, a *context.Handler, or any other arbitrary value.

Common situations: Passing an untyped function literal `func(ctx *context.Context){...}` instead of an iris/context.Handler; passing `count` (int) instead of `&count` (*int) as the occurrence counter; refactoring code that previously removed handlers by name.

Related errors


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