gofiber/fiber · error

fiber: keyauth error_uri must be absolute

Error message

fiber: keyauth error_uri must be absolute

What it means

When Config.ErrorURI is set, keyauth parses it with url.Parse and requires the result to be absolute (u.IsAbs()). A relative URI panics because RFC 6750 error_uri must be an absolute URI the client can dereference. This also rejects malformed URIs that fail to parse.

Solutions

  1. Provide an absolute URL with a scheme and host, e.g. "https://docs.example.com/auth/errors".
  2. Build the URL from a configured base: fmt.Sprintf("%s/auth/errors", baseURL) where baseURL always includes the scheme.
  3. If you only have a relative path, drop ErrorURI (it is optional).

Example fix

// before
app.Use(keyauth.New(keyauth.Config{
    Validator: v,
    Error:     keyauth.ErrorInvalidToken,
    ErrorURI:  "/docs/auth",
}))

// after
app.Use(keyauth.New(keyauth.Config{
    Validator: v,
    Error:     keyauth.ErrorInvalidToken,
    ErrorURI:  "https://docs.example.com/auth",
}))
Defensive patterns

Strategy: validation

Validate before calling

if cfg.ErrorURI != "" {
    u, err := url.Parse(cfg.ErrorURI)
    if err != nil || !u.IsAbs() {
        log.Fatalf("keyauth: ErrorURI must be absolute, got %q", cfg.ErrorURI)
    }
}

Type guard

func isAbsoluteURL(s string) bool {
    u, err := url.Parse(s)
    return err == nil && u.IsAbs()
}

Prevention

When it happens

Trigger: ErrorURI: "/docs/auth", "docs.example.com/auth" (no scheme), or any value where url.Parse succeeds but Scheme/Host are empty. Also triggered by a typo'd scheme like htt://.

Common situations: Using a site-relative docs link instead of a fully-qualified URL; building ErrorURI from a hostname variable that is sometimes empty; copy-pasting a path that omits the https:// prefix.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/3dd0367705034193. Report an issue: GitHub.

Appendix: source

Thrown at middleware/keyauth/config.go:147

		cfg.Challenge = fmt.Sprintf("ApiKey realm=%q", cfg.Realm)
	}

	if cfg.Error != "" {
		switch cfg.Error {
		case ErrorInvalidRequest, ErrorInvalidToken, ErrorInsufficientScope:
		default:
			panic("fiber: keyauth unsupported error token")
		}
	}
	if cfg.ErrorDescription != "" && cfg.Error == "" {
		panic("fiber: keyauth error_description requires error")
	}
	if cfg.ErrorURI != "" {
		if cfg.Error == "" {
			panic("fiber: keyauth error_uri requires error")
		}
		if u, err := url.Parse(cfg.ErrorURI); err != nil || !u.IsAbs() {
			panic("fiber: keyauth error_uri must be absolute")
		}
	}
	if cfg.Error == ErrorInsufficientScope {
		if cfg.Scope == "" {
			panic("fiber: keyauth insufficient_scope requires scope")
		}
		for scope := range strings.SplitSeq(cfg.Scope, " ") {
			if scope == "" || !isScopeToken(scope) {
				panic("fiber: keyauth scope contains invalid token")
			}
		}
	} else if cfg.Scope != "" {
		panic("fiber: keyauth scope requires insufficient_scope error")
	}

	return cfg
}

View on GitHub (pinned to a105acad6c)