kataras/iris · error

iris: switch: hosts: loop detected between expression: "%s"

Error message

iris: switch: hosts: loop detected between expression: "%s" and target host: "%s"

What it means

While resolving each host case, hostApp checks whether the target host matches the host's own pattern regex. If it does, registering the case would create an infinite redirect loop (the host redirects to itself), so it panics with a message naming both the expression and the target. This is a startup-time safety check for redirect cycles.

Source

Thrown at apps/switch_hosts.go:109

	case context.Application:
		return target.(*iris.Application)
	case string:
		// Check if the given target is an application name, if so
		// we must not redirect (loop) we must serve the request
		// using that app.
		if targetApp, ok := context.GetApplication(target); ok {
			// It's always iris.Application so we are totally safe here.
			return targetApp.(*iris.Application)
		}
		// If it's a real host, warn the user of invalid input.
		u, err := url.Parse(target)
		if err == nil && u.IsAbs() {
			// remember, we redirect hosts, not full URLs here.
			panic(fmt.Sprintf(`iris: switch: hosts: invalid target host: "%s"`, target))
		}

		if regex := regexp.MustCompile(host.Pattern); regex.MatchString(target) {
			panic(fmt.Sprintf(`iris: switch: hosts: loop detected between expression: "%s" and target host: "%s"`, host.Pattern, host.Target))
		}

		return newHostRedirectApp(target, HostsRedirectCode)
	default:
		panic(fmt.Sprintf("iris: switch: hosts: invalid target type: %T", target))
	}
}

func hostFilter(expr string) iris.Filter {
	regex := regexp.MustCompile(expr)
	return func(ctx iris.Context) bool {
		return regex.MatchString(ctx.Host())
	}
}

// HostsRedirectCode is the default status code is used
// to redirect a matching host to a url.
var HostsRedirectCode = iris.StatusMovedPermanently

View on GitHub (pinned to 7bedaf55a0)

Solutions

  1. Narrow the host pattern so it excludes the target host
  2. Point the target at a different domain than the pattern matches
  3. Swap the redirect direction (apex → www instead of www → apex) if that was the intent

Example fix

// before
hosts := iris.Hosts{"^(.*\\.)?example.com$": "www.example.com"}
// after
hosts := iris.Hosts{"^example\\.com$": "www.example.com"}
Defensive patterns

Strategy: validation

Validate before calling

for pattern, target := range hosts {
	if regexp.MustCompile(pattern).MatchString(target) {
		return fmt.Errorf("host pattern %q matches its own target %q", pattern, target)
	}
}

Try / catch

defer func() {
	if r := recover(); r != nil {
		if s, ok := r.(string); ok && strings.Contains(s, "loop detected") {
			log.Fatalf("host redirect loop: %s", s)
		}
		panic(r)
	}
}()

Prevention

When it happens

Trigger: Configuring a Hosts entry where the pattern (e.g. "^(.*\.)?example.com$") also matches its own target (e.g. target "www.example.com" under a pattern matching example.com subdomains).

Common situations: Wildcard patterns like ".*" or overly broad regexes paired with a target in the same domain; www → apex redirects written in the wrong direction; config refactors that copy a pattern across entries.

Related errors


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