gohugoio/hugo · error

failed to get remote ref %q: %w

Error message

failed to get remote ref %q: %w

What it means

When resolving external `$ref`s in an OpenAPI document, refs with a scheme and host are fetched with `resources.GetRemote` (tpl/openapi/openapi3/openapi3.go:175). If that fetch fails — network error, non-2xx status, timeout, or blocked by Hugo's HTTP security policy — the resolver wraps the underlying error with the ref URL in this message.

Source

Thrown at tpl/openapi/openapi3/openapi3.go:175

	return v, nil
}

type refResolver struct {
	ctx     context.Context
	idm     identity.Manager
	opts    unmarshalOptions
	relBase string
	ns      *Namespace
}

// resolveExternalRef resolves external references in OpenAPI documents by either fetching
// remote URLs or loading local files from the assets directory, depending on the reference location.
func (r *refResolver) resolveExternalRef(loader *kopenapi3.Loader, loc *url.URL) ([]byte, error) {
	if loc.Scheme != "" && loc.Host != "" {
		res, err := r.ns.resourcesNs.GetRemote(loc.String(), r.opts.GetRemote)
		if err != nil {
			return nil, fmt.Errorf("failed to get remote ref %q: %w", loc.String(), err)
		}
		content, err := resources.InternalResourceSourceContent(r.ctx, res)
		if err != nil {
			return nil, fmt.Errorf("failed to read remote ref %q: %w", loc.String(), err)
		}
		r.idm.AddIdentity(identity.FirstIdentity(res))
		return []byte(content), nil
	}

	var filename string
	if strings.HasPrefix(loc.Path, "/") {
		filename = loc.Path
	} else {
		filename = path.Join(r.relBase, loc.Path)
	}

	res := r.ns.resourcesNs.Get(filename)
	if res == nil {

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Check the wrapped error: fix the URL, network access, or the remote server's response.
  2. Pass required headers/options via the options map: `{{ openapi3.Unmarshal $r (dict "getRemote" (dict "headers" (dict "Authorization" ...))) }}` (keep tokens in env config, not templates).
  3. Allow the domain in your Hugo config `security.http.urls` if the fetch is being blocked.
  4. Vendor the referenced schema into `assets/` and change the `$ref` to a local path so no network is needed at build time.

Example fix

# before: build depends on unreachable remote $ref
$ref: "https://schemas.example.com/pet.yaml"
# after: vendored locally under assets/
$ref: "./schemas/pet.yaml"
Defensive patterns

Strategy: retry

Validate before calling

# pre-flight the remote $ref targets referenced by the spec
curl -sfI https://example.com/schemas/user.yaml >/dev/null || echo "unreachable ref"

Try / catch

{{/* build-time: remote $ref fetch failures surface as build errors; use try where available */}}
{{ $r := try (openapi3.Unmarshal $spec) }}
{{ with $r.Err }}{{ warnf "openapi remote ref failed: %s" . }}{{ else }}{{ $doc := $r.Value }}{{ end }}

Prevention

When it happens

Trigger: Unmarshalling a spec containing `$ref: "https://example.com/schemas/foo.yaml"` where the remote host is unreachable, returns 404/403/5xx, requires auth headers not supplied via the `getRemote` options, or is disallowed by `security.http.urls` in the Hugo config.

Common situations: CI environments without outbound network access, expired or moved schema URLs, missing auth headers for private schema registries, Hugo's security allowlist not including the ref's domain, and proxy/TLS issues.

Related errors


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