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

  1. Use a full 'scheme://' protocol form unless the BaseURL is genuinely opaque.
  2. Construct the opaque BaseURL from scratch via NewBaseURLFromString('mailto:user@example.com').
  3. 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

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


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)