gohugoio/hugo · error

cannot determine BaseURL for protocol %q

Error message

cannot determine BaseURL for protocol %q

What it means

`BaseURL.WithProtocol` rewrites the scheme of the site's baseURL, supporting both full protocols (`webcal://`) and opaque ones (`mailto:`). An opaque protocol (ending in `:` without `//`) requires the underlying URL to have an opaque part; if the current baseURL has none, Hugo cannot construct a meaningful URL and returns this error.

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 8a468df065)

Solutions

  1. Use the full `scheme://` form in the output format's `protocol` setting (e.g. `webcal://`, not `webcal:`).
  2. If an opaque scheme is genuinely intended, ensure the baseURL is itself opaque; otherwise reconsider the design.
  3. Check `hugo config` for the offending `protocol` value under outputFormats.

Example fix

# before (hugo.toml)
[outputFormats.Calendar]
protocol = "webcal:"

# after
[outputFormats.Calendar]
protocol = "webcal://"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(baseURL)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
    return fmt.Errorf("baseURL must be http(s), got %q", baseURL)
}

Try / catch

if err != nil {
    // report the unsupported scheme and fix baseURL in config; do not retry
}

Prevention

When it happens

Trigger: An output format or media type configured with a `protocol` like `mailto:` or `tel:` applied to a normal hierarchical baseURL (e.g. `https://example.com/`) — `WithProtocol("mailto:")` on such a URL has no opaque component to carry the address.

Common situations: Custom `[outputFormats]` entries setting `protocol = "something:"` when `something://` was intended; experimenting with webcal/mailto protocols on standard site baseURLs; typo dropping the slashes from a protocol value.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/35e5f9b54a6493ab.json. Report an issue: GitHub ↗.