{"id":"ff2e41ea17b6a558","repo":"gohugoio/hugo","slug":"can-t-make-permalink-from-absolute-link-q","errorCode":null,"errorMessage":"can't make permalink from absolute link %q","messagePattern":"can't make permalink from absolute link %q","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"common/paths/url.go","lineNumber":71,"sourceCode":"// MakePermalink combines base URL with content path to create full URL paths.\n// Example\n//\n//\tbase:   http://spf13.com/\n//\tpath:   post/how-i-blog\n//\tresult: http://spf13.com/post/how-i-blog\nfunc MakePermalink(host, plink string) *url.URL {\n\tbase, err := url.Parse(host)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tp, err := url.Parse(plink)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tif p.Host != \"\" {\n\t\tpanic(fmt.Errorf(\"can't make permalink from absolute link %q\", plink))\n\t}\n\n\tbase.Path = path.Join(base.Path, p.Path)\n\tbase.Fragment = p.Fragment\n\tbase.RawQuery = p.RawQuery\n\n\t// path.Join will strip off the last /, so put it back if it was there.\n\thadTrailingSlash := (plink == \"\" && strings.HasSuffix(host, \"/\")) || strings.HasSuffix(p.Path, \"/\")\n\tif hadTrailingSlash && !strings.HasSuffix(base.Path, \"/\") {\n\t\tbase.Path = base.Path + \"/\"\n\t}\n\n\treturn base\n}\n\n// AddContextRoot adds the context root to an URL if it's not already set.\n// For relative URL entries on sites with a base url with a context root set (i.e. http://example.com/mysite),\n// relative URLs must not include the context root if canonifyURLs is enabled. But if it's disabled, it must be set.","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/common/paths/url.go#L53-L89","documentation":"`paths.MakePermalink` joins a base URL (usually the site's baseURL) with a relative link to form a permalink. If the second argument parses to a URL with a non-empty Host — i.e. it's already absolute like `https://example.com/foo` — joining is ambiguous and the function panics with this error. It's an internal invariant: callers must pass site-relative paths.","triggerScenarios":"Code paths that build permalinks (page URL resolution, `permalinks` config expansion, relURL/absURL-adjacent internals) receiving a link that already contains a scheme+host, e.g. a `url:` front-matter value or permalink pattern that expands to a full absolute URL.","commonSituations":"Setting `url: https://example.com/post/` in page front matter instead of `url: /post/`; permalink tokens or slugs containing a full URL; aliases or configuration values pasted with the domain included.","solutions":["Change the offending front-matter `url`/`slug` or permalink pattern to a site-relative path (starting with `/`), leaving the host to baseURL.","Search content for absolute URLs in `url:` fields: `grep -rn 'url: *http' content/`.","If you need an external link, use an external-link mechanism (e.g. a headless page or link in front matter consumed by templates), not the page URL."],"exampleFix":"# before (front matter)\nurl: https://example.com/post/how-i-blog/\n\n# after\nurl: /post/how-i-blog/","handlingStrategy":"validation","validationCode":"u, err := url.Parse(link)\nif err == nil && u.IsAbs() {\n    // already absolute: use as-is, do not pass to permalink construction\n}","typeGuard":"func isAbsURL(s string) bool {\n    u, err := url.Parse(s)\n    return err == nil && u.IsAbs()\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"absolute link\") {\n    // use the original URL directly instead of relURL/absURL-style processing\n}","preventionTips":["Check IsAbs() before feeding links into permalink helpers; absolute URLs should bypass them","In templates, branch on absolute vs relative links before calling relURL/absURL","Store internal links as root-relative paths, not full URLs with scheme+host"],"tags":["hugo","urls","permalinks","panic"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}