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
- Check the wrapped error: fix the URL, network access, or the remote server's response.
- Pass required headers/options via the options map: `{{ openapi3.Unmarshal $r (dict "getRemote" (dict "headers" (dict "Authorization" ...))) }}` (keep tokens in env config, not templates).
- Allow the domain in your Hugo config `security.http.urls` if the fetch is being blocked.
- 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
- Vendor remote $refs locally when possible so builds don't depend on external hosts
- Verify remote ref URLs are reachable in CI before the Hugo build
- Treat transient network failures as retryable at the CI level (re-run the build), not by looping in templates
- Pin remote spec URLs to versioned/immutable paths so refs don't 404 after upstream changes
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
- must provide a Resource and optionally an options map
- no Key set in Resource
- MIME %q not supported
- local ref %q not found
- stopped after 10 redirects
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/86a564fe6a8946a5.json.
Report an issue: GitHub ↗.