{"id":"35e5f9b54a6493ab","repo":"gohugoio/hugo","slug":"cannot-determine-baseurl-for-protocol-q","errorCode":null,"errorMessage":"cannot determine BaseURL for protocol %q","messagePattern":"cannot determine BaseURL for protocol %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/urls/baseURL.go","lineNumber":72,"sourceCode":"func (b BaseURL) WithProtocol(protocol string) (BaseURL, error) {\n\tu := b.URL()\n\n\tscheme := protocol\n\tisFullProtocol := strings.HasSuffix(scheme, \"://\")\n\tisOpaqueProtocol := strings.HasSuffix(scheme, \":\")\n\n\tif isFullProtocol {\n\t\tscheme = strings.TrimSuffix(scheme, \"://\")\n\t} else if isOpaqueProtocol {\n\t\tscheme = strings.TrimSuffix(scheme, \":\")\n\t}\n\n\tu.Scheme = scheme\n\n\tif isFullProtocol && u.Opaque != \"\" {\n\t\tu.Opaque = \"//\" + u.Opaque\n\t} else if isOpaqueProtocol && u.Opaque == \"\" {\n\t\treturn BaseURL{}, fmt.Errorf(\"cannot determine BaseURL for protocol %q\", protocol)\n\t}\n\n\treturn newBaseURLFromURL(u)\n}\n\nfunc (b BaseURL) WithPort(port int) (BaseURL, error) {\n\tu := b.URL()\n\tu.Host = u.Hostname() + \":\" + strconv.Itoa(port)\n\treturn newBaseURLFromURL(u)\n}\n\n// URL returns a copy of the internal URL.\n// The copy can be safely used and modified.\nfunc (b BaseURL) URL() *url.URL {\n\tc := *b.url\n\treturn &c\n}\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/common/urls/baseURL.go#L54-L90","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Use the full `scheme://` form in the output format's `protocol` setting (e.g. `webcal://`, not `webcal:`).","If an opaque scheme is genuinely intended, ensure the baseURL is itself opaque; otherwise reconsider the design.","Check `hugo config` for the offending `protocol` value under outputFormats."],"exampleFix":"# before (hugo.toml)\n[outputFormats.Calendar]\nprotocol = \"webcal:\"\n\n# after\n[outputFormats.Calendar]\nprotocol = \"webcal://\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(baseURL)\nif err != nil || (u.Scheme != \"http\" && u.Scheme != \"https\") {\n    return fmt.Errorf(\"baseURL must be http(s), got %q\", baseURL)\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    // report the unsupported scheme and fix baseURL in config; do not retry\n}","preventionTips":["Set baseURL in config with an explicit http:// or https:// scheme","Avoid exotic schemes (ftp, file, custom) in baseURL; Hugo only maps ports for known protocols","Validate baseURL parse + scheme during config load in CI"],"tags":["hugo","urls","config","output-formats"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}