gohugoio/hugo · error

must provide a Resource and optionally an options map

Error message

must provide a Resource and optionally an options map

What it means

Thrown by openapi3.Unmarshal when the variadic args length is not 1 or 2. The function signature is Unmarshal(ctx, args...) expecting exactly one Resource plus an optional options map. Zero args, or more than two args, triggers this.

Solutions

  1. Pass exactly one Resource and an optional options map: {{ $r | openapi3.Unmarshal }} or {{ openapi3.Unmarshal $r $opts }}.
  2. Ensure the first argument is the resource obtained from resources.Get / resources.GetRemote, not a string path.
  3. Remove any extra positional arguments beyond the optional options map.

Example fix

// before
{{ openapi3.Unmarshal "api.yaml" }}
// after
{{ resources.Get "api.yaml" | openapi3.Unmarshal }}
Defensive patterns

Strategy: validation

Validate before calling

{{ with resources.Get "api.yaml" }}{{ openapi3.Unmarshal . }}{{ end }}

Type guard

// Verify the value implements the expected resource interface before calling
func isUnmarshableResource(v any) bool {
    _, ok := v.(resource.UnmarshableResource)
    return ok
}

Prevention

When it happens

Trigger: Calling {{ $doc := resources.Get "api.yaml" | openapi3.Unmarshal }} incorrectly, or calling openapi3.Unmarshal with no resource, or passing three or more arguments like {{ openapi3.Unmarshal $r $opts $extra }}.

Common situations: Forgetting to pipe a resource into Unmarshal; passing both a resource and a separate options map positionally in the wrong order; typos adding extra arguments.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/8afb5842e2524926. Report an issue: GitHub.

Appendix: source

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

// OpenAPIDocument represents an OpenAPI 3 document.
type OpenAPIDocument struct {
	*kopenapi3.T
	identityGroup identity.Identity
}

func (o *OpenAPIDocument) GetIdentityGroup() identity.Identity {
	return o.identityGroup
}

type unmarshalOptions struct {
	// Options passed to resources.GetRemote when resolving remote $ref.
	GetRemote map[string]any
}

// Unmarshal unmarshals the given resource into an OpenAPI 3 document.
func (ns *Namespace) Unmarshal(ctx context.Context, args ...any) (*OpenAPIDocument, error) {
	if len(args) < 1 || len(args) > 2 {
		return nil, errors.New("must provide a Resource and optionally an options map")
	}

	r := args[0].(resource.UnmarshableResource)
	key := r.Key()
	if key == "" {
		return nil, errors.New("no Key set in Resource")
	}

	var opts unmarshalOptions
	if len(args) > 1 {
		optsm, err := hmaps.ToStringMapE(args[1])
		if err != nil {
			return nil, err
		}
		if err := mapstructure.WeakDecode(optsm, &opts); err != nil {
			return nil, err
		}
		key += "_" + hashing.HashString(optsm)

View on GitHub (pinned to 52c9bd7908)