gohugoio/hugo · error
cannot determine BaseURL for protocol
Error message
cannot determine BaseURL for protocol %q
What it means
Returned by BaseURL.WithProtocol when the supplied protocol is opaque (ends with a single ':', e.g. 'mailto:') but the BaseURL's underlying URL has no opaque component to attach it to. WithProtocol only supports opaque protocols when the existing URL is itself opaque; otherwise it cannot construct a valid BaseURL.
Solutions
- Use a full 'scheme://' protocol form unless the BaseURL is genuinely opaque.
- Construct the opaque BaseURL from scratch via NewBaseURLFromString('mailto:user@example.com').
- Avoid WithProtocol for opaque schemes on path-based BaseURLs.
Example fix
// before
b,_ := urls.NewBaseURLFromString("https://site.com/")
b.WithProtocol("mailto:")
// after
b,_ := urls.NewBaseURLFromString("mailto:user@example.com") Defensive patterns
Strategy: validation
Validate before calling
func canWithProtocol(b urls.BaseURL, protocol string) bool {
opaque := strings.HasSuffix(protocol, ":") && !strings.HasSuffix(protocol, "://")
return !opaque || b.URL().Opaque != ""
} Prevention
- Use 'scheme://' protocols with normal BaseURLs.
- Build opaque BaseURLs from scratch via NewBaseURLFromString for mailto:/tel:.
- Avoid relabeling path-based BaseURLs with opaque schemes.
When it happens
Trigger: Calling baseURL.WithProtocol("mailto:") (or any ':' suffix without '//') on a BaseURL whose URL.Opaque is empty because the original baseURL was a normal scheme://path form.
Common situations: Output-format or media-type configuration that tries to relabel a regular http(s) BaseURL with an opaque protocol like 'mailto:', 'tel:', or 'javascript:'.
Related errors
- --appendPort=false not supported when in multihost mode
- cache dir contains unresolved placeholders
- cannot convert to time.Duration
- cannot unmarshal CSV into %T: invalid targetType: expected…
- cannot vendor module
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/35e5f9b54a6493ab.
Report an issue: GitHub.
Appendix: source
Thrown at common/urls/baseURL.go:72
func (b BaseURL) WithProtocol(protocol string) (BaseURL, error) {
u := b.URL()
scheme := protocol
isFullProtocol := strings.HasSuffix(scheme, "://")
isOpaqueProtocol := strings.HasSuffix(scheme, ":")
if isFullProtocol {
scheme = strings.TrimSuffix(scheme, "://")
} else if isOpaqueProtocol {
scheme = strings.TrimSuffix(scheme, ":")
}
u.Scheme = scheme
if isFullProtocol && u.Opaque != "" {
u.Opaque = "//" + u.Opaque
} else if isOpaqueProtocol && u.Opaque == "" {
return BaseURL{}, fmt.Errorf("cannot determine BaseURL for protocol %q", protocol)
}
return newBaseURLFromURL(u)
}
func (b BaseURL) WithPort(port int) (BaseURL, error) {
u := b.URL()
u.Host = u.Hostname() + ":" + strconv.Itoa(port)
return newBaseURLFromURL(u)
}
// URL returns a copy of the internal URL.
// The copy can be safely used and modified.
func (b BaseURL) URL() *url.URL {
c := *b.url
return &c
}
View on GitHub (pinned to 52c9bd7908)