gohugoio/hugo · error

failed to parse URL for resource %s: %w

Error message

failed to parse URL for resource %s: %w

What it means

`resources.GetRemote` (Client.FromRemote) first parses the given URI with `url.Parse`. If the string is not a syntactically valid URL, Hugo fails fast with this wrapped parse error rather than attempting a request. Note that `url.Parse` is lenient, so this usually means genuinely malformed input like invalid control characters or bad percent-encoding.

Source

Thrown at resources/resource_factories/create/remote.go:198

				if time.Since(lastChange) < 10*time.Second {
					// The user is typing, check more often.
					return 0, nil
				}

				// Increase the interval to avoid hammering the server.
				interval += 1 * time.Second

				return interval, nil
			},
		})
}

// FromRemote expects one or n-parts of a URL to a resource
// If you provide multiple parts they will be joined together to the final URL.
func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resource, error) {
	rURL, err := url.Parse(uri)
	if err != nil {
		return nil, fmt.Errorf("failed to parse URL for resource %s: %w", uri, err)
	}

	method := "GET"
	if s, _, ok := hmaps.LookupEqualFold(optionsm, "method"); ok {
		method = strings.ToUpper(s.(string))
	}
	isHeadMethod := method == "HEAD"

	optionsm = maps.Clone(optionsm)

	// Extract timeout before computing cache keys: it only affects fetch behaviour,
	// not the cached content, so it must not influence the cache key.
	var perRequestTimeout time.Duration
	if v, k, ok := hmaps.LookupEqualFold(optionsm, "timeout"); ok {
		d, err := cast.ToDurationE(v)
		if err != nil {
			return nil, fmt.Errorf("invalid timeout for resource %s: %w", uri, err)
		}

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Trim and validate the URL before use: `{{ $u := trim $url " \n" }}`.
  2. Properly encode query parameters (e.g. `querify` or `urlquery`) instead of concatenating raw values.
  3. Print the exact string passed (`warnf "url=%q" $url`) to spot hidden whitespace or bad percent-escapes in the data source.

Example fix

{{/* before */}}
{{ $r := resources.GetRemote (printf "%s?q=%s" .Params.api .Params.query) }}
{{/* after */}}
{{ $u := printf "%s?%s" (trim .Params.api " \n") (querify "q" .Params.query) }}
{{ $r := resources.GetRemote $u }}
Defensive patterns

Strategy: validation

Validate before calling

{{ $url := .Params.remote_url }}
{{ $u := urls.Parse $url }}
{{ if or (not $u.Scheme) (not $u.Host) }}
  {{ errorf "invalid remote resource URL: %q" $url }}
{{ end }}
{{ $r := resources.GetRemote $url }}

Prevention

When it happens

Trigger: Calling `resources.GetRemote $url` in a template where `$url` contains invalid characters (spaces, newlines, unescaped `%` sequences like `%zz`, control chars), or where multiple URL parts were joined/interpolated incorrectly (e.g. `printf` with stray whitespace from front matter).

Common situations: URLs read from front matter or data files with trailing newlines/spaces, hand-built query strings with unencoded values, CSV/JSON data containing malformed URLs, or template string concatenation inserting a literal `\n`.

Related errors


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