gohugoio/hugo · error

local ref %q not found

Error message

local ref %q not found

What it means

For external `$ref`s without a scheme/host, Hugo resolves them as local files: absolute paths from the assets root, relative paths joined against the directory of the spec resource, then looked up with `resources.Get` (tpl/openapi/openapi3/openapi3.go:192-194). If no asset exists at the computed path, resolution fails with the ref string.

Source

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

		}
		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 {
		return nil, fmt.Errorf("local ref %q not found", loc.String())
	}
	content, err := resources.InternalResourceSourceContent(r.ctx, res)
	if err != nil {
		return nil, fmt.Errorf("failed to read local ref %q: %w", loc.String(), err)
	}
	r.idm.AddIdentity(identity.FirstIdentity(res))
	return []byte(content), nil
}

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Place the referenced files under `assets/` at the path the ref resolves to, relative to the spec's own directory.
  2. Fix the `$ref` path (and case) to match the actual file location; use an absolute-from-assets path like `/api/schemas/pet.yaml` if relative resolution is ambiguous.
  3. Ensure the main spec itself is loaded from `assets/` via `resources.Get` so relative refs resolve against its directory.
  4. Alternatively bundle the spec into a single file (e.g. with an OpenAPI bundler) to eliminate local refs.

Example fix

# before: file lives at static/schemas/pet.yaml
$ref: "./schemas/pet.yaml"
# after: file moved to assets/api/schemas/pet.yaml next to the spec
$ref: "./schemas/pet.yaml"  # now resolvable via resources.Get
Defensive patterns

Strategy: validation

Validate before calling

# validate the spec's internal $refs before building
npx @redocly/cli lint api/openapi.yaml

Try / catch

{{ $r := try (openapi3.Unmarshal $spec) }}
{{ with $r.Err }}{{ errorf "broken $ref in OpenAPI spec: %s" . }}{{ end }}

Prevention

When it happens

Trigger: A spec in `assets/api/openapi.yaml` containing `$ref: "./schemas/pet.yaml"` when `assets/api/schemas/pet.yaml` doesn't exist; refs with wrong relative paths, wrong case, or pointing outside the assets directory (e.g. into `static/`).

Common situations: Referenced schema files kept in `static/` or the project root instead of `assets/`, path case mismatches surfacing on Linux CI, relative refs written for a different base directory than where the spec resource actually lives, or the spec loaded via a path where `relBase` can't be computed.

Related errors


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