argoproj/argo-workflows · error
logout redirect URL must be an absolute HTTP(S) URL without
Error message
logout redirect URL must be an absolute HTTP(S) URL without user info or a fragment: %q
What it means
ValidateRedirectURL checks the operator-supplied post-logout redirect URL configured on the Argo Server. It rejects any non-empty value that is not an absolute HTTP(S) URL (the shared parseAbsoluteHTTPURL helper also excludes user info and fragments). This guards against malformed or unsafe logout redirects.
Source
Thrown at server/logout/logout.go:40
// If the provider end-session URL is invalid, the handler falls back to the local redirect and returns the validation error.
func NewHandler(baseHRef, redirectURL string, secure bool, logoutURL, clientID string) (*Handler, error) {
baseHRef = authcookie.NormalizePath(baseHRef)
cookiePaths := []string{baseHRef}
if legacyCookiePath := strings.TrimSuffix(baseHRef, "/"); legacyCookiePath != "" {
cookiePaths = append(cookiePaths, legacyCookiePath)
}
if redirectURL == "" {
redirectURL = baseHRef
logoutURL = ""
}
finalRedirectURL, err := constructLogoutURL(logoutURL, clientID, redirectURL)
return &Handler{cookiePaths: cookiePaths, redirectURL: finalRedirectURL, secure: secure}, err
}
// ValidateRedirectURL validates the optional post-logout redirect URL supplied by an operator.
func ValidateRedirectURL(redirectURL string) error {
if redirectURL != "" && !isAbsoluteHTTPURL(redirectURL) {
return fmt.Errorf("logout redirect URL must be an absolute HTTP(S) URL without user info or a fragment: %q", redirectURL)
}
return nil
}
func isAbsoluteHTTPURL(rawURL string) bool {
_, ok := parseAbsoluteHTTPURL(rawURL)
return ok
}
func parseAbsoluteHTTPURL(rawURL string) (*url.URL, bool) {
parsedURL, err := url.Parse(rawURL)
if err != nil || parsedURL.Hostname() == "" || parsedURL.User != nil || parsedURL.Fragment != "" ||
(!strings.EqualFold(parsedURL.Scheme, "http") && !strings.EqualFold(parsedURL.Scheme, "https")) {
return nil, false
}
return parsedURL, true
}
View on GitHub (pinned to 35bff19146)
Solutions
- Set the URL to a fully qualified absolute URL starting with http:// or https://
- Remove any #fragment and user:password@ userinfo from the URL
- If no post-logout redirect is desired, leave the value empty (empty is valid)
Example fix
// before ARGO_SERVER_REDIRECT_URL_AFTER_LOGOUT=/goodbye // after ARGO_SERVER_REDIRECT_URL_AFTER_LOGOUT=https://sso.example.com/logout
Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(cfg.LogoutRedirectURL)
if cfg.LogoutRedirectURL != "" && (err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" || u.User != nil || u.Fragment != "") {
return fmt.Errorf("invalid logout redirect URL: %q", cfg.LogoutRedirectURL)
} Type guard
func isSafeAbsoluteURL(raw string) bool {
u, err := url.Parse(raw)
return err == nil && raw != "" && (u.Scheme == "http" || u.Scheme == "https") && u.Host != "" && u.User == nil && u.Fragment == ""
} Try / catch
if err := logout.ValidateRedirectURL(cfg.LogoutRedirectURL); err != nil {
log.Fatalf("bad logout redirect URL: %v", err)
} Prevention
- Always configure full https:// URLs for operator-provided redirects
- Strip #fragments and credentials before persisting config
- Validate the value at config-load time, not at logout time
When it happens
Trigger: Starting `argo server` with a logout redirect URL (e.g. via --redirect-url-after-logout or env var) that is relative ("/logged-out"), not http(s) ("ftp://x"), contains userinfo ("https://user:pass@host") or a fragment ("https://host#frag").
Common situations: Operators copying OIDC provider logout URLs with fragments, mistyping the flag, or setting a relative path believing relative redirects are allowed.
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- oidc end-session endpoint must be an absolute HTTP(S) URL wi
- invalid TTL
- single branch mode without a branch specified
- memoization configmap doesn't have %s label, refusing to use
- artifact driver %s not found
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/5102fa6258f7e0c7.
Report an issue: GitHub.