bytebase/bytebase · error
%s must not carry a query string
Error message
%s must not carry a query string
What it means
NormalizeExternalURL rejects URLs that contain a query string (RawQuery non-empty or ForceQuery set, i.e. a trailing "?"). The external URL is used as an OAuth redirect base, so a query component would corrupt redirect URLs.
Source
Thrown at backend/common/util.go:142
func NormalizeExternalURL(externalURL string) (string, error) {
r := strings.TrimSpace(externalURL)
r = strings.TrimSuffix(r, "/")
u, err := url.Parse(r)
if err != nil {
return "", errors.Wrapf(err, "%s malformed", externalURL)
}
scheme := strings.ToLower(u.Scheme)
if scheme != "http" && scheme != "https" {
return "", errors.Errorf("%s must start with http:// or https://", externalURL)
}
if u.Host == "" {
return "", errors.Errorf("%s must name a host", externalURL)
}
if u.User != nil {
return "", errors.Errorf("%s must not carry userinfo", externalURL)
}
if u.RawQuery != "" || u.ForceQuery {
return "", errors.Errorf("%s must not carry a query string", externalURL)
}
if u.Fragment != "" || u.RawFragment != "" {
return "", errors.Errorf("%s must not carry a fragment", externalURL)
}
host := strings.ToLower(u.Host)
port := u.Port()
if port != "" {
// The external URL is used as the redirectURL in the get token process of OAuth, and the
// RedirectURL needs to be consistent with the RedirectURL in the get code process.
// The frontend gets it through window.location.origin in the get code
// process, so port 80/443 need to be cropped.
if (scheme == "http" && port == "80") || (scheme == "https" && port == "443") {
host = strings.ToLower(u.Hostname())
if strings.Contains(host, ":") {
host = "[" + host + "]"
}
}View on GitHub (pinned to 1870550677)
Solutions
- Strip everything from "?" onward; configure only scheme://host[:port][/path].
- Copy the origin from the browser address bar up to (but not including) the "?".
- Re-run the workspace settings validation after cleaning the URL.
Example fix
// before
NormalizeExternalURL("https://example.com/?utm_source=x")
// after
NormalizeExternalURL("https://example.com") Defensive patterns
Strategy: validation
Validate before calling
u, _ := url.Parse(strings.TrimSpace(externalURL))
if u.RawQuery != "" || u.ForceQuery {
return errors.New("external URL must not contain a query string; strip everything after '?'")
} Try / catch
normalized, err := common.NormalizeExternalURL(u)
if err != nil && strings.Contains(err.Error(), "must not carry a query string") {
if cleaned := strings.SplitN(u, "?", 2)[0]; cleaned != "" {
normalized, err = common.NormalizeExternalURL(cleaned)
}
} Prevention
- Copy only the origin (scheme://host[:port][/path]) from the address bar
- Strip utm_* and other tracking parameters before configuring
- Automatically cut at '?' in admin tooling that accepts URLs
When it happens
Trigger: Calling NormalizeExternalURL with "https://example.com/?utm_source=x" or "https://example.com/?"; reached via the workspace external URL validation call sites.
Common situations: Copying a full page URL including tracking parameters (utm_*, session IDs) instead of the bare origin.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- failed to create HTTP request: %s
- %s malformed
- %s must start with http:// or https://
- %s must name a host
- %s must not carry userinfo
AI-assisted analysis of bytebase/bytebase@1870550677 (2026-09-06).
Data as JSON: /api/errors/ae1ee5a09b977657.
Report an issue: GitHub.