gohugoio/hugo · error

value has type %s; should be %s

Error message

value has type %s; should be %s

What it means

Returned by prepareArg when the argument value is valid but not assignable to the target parameter type and not an int-like convertible value. This is the general type-mismatch path during argument coercion (func calls, map key indexing, the call builtin). The first %s is the value's actual type; the second %s is the expected type.

Source

Thrown at tpl/internal/go_templates/texttemplate/funcs.go:161

}

// prepareArg checks if value can be used as an argument of type argType, and
// converts an invalid value to appropriate zero if possible.
func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error) {
	if !value.IsValid() {
		if !canBeNil(argType) {
			return reflect.Value{}, fmt.Errorf("value is nil; should be of type %s", argType)
		}
		value = reflect.Zero(argType)
	}
	if value.Type().AssignableTo(argType) {
		return value, nil
	}
	if intLike(value.Kind()) && intLike(argType.Kind()) && value.Type().ConvertibleTo(argType) {
		value = value.Convert(argType)
		return value, nil
	}
	return reflect.Value{}, fmt.Errorf("value has type %s; should be %s", value.Type(), argType)
}

func intLike(typ reflect.Kind) bool {
	switch typ {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return true
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return true
	}
	return false
}

// indexArg checks if a reflect.Value can be used as an index, and converts it to int if possible.
func indexArg(index reflect.Value, cap int) (int, error) {
	var x int64
	switch index.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		x = index.Int()

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Align the template-supplied value's type with the func/map parameter type.
  2. Widen the func parameter to interface{} and convert inside, returning an error on mismatch.
  3. Convert the value in the template via a helper func before passing it.
  4. Add type assertions/conversions in the data preparation layer.

Example fix

// before
// func: func(n int) string ; data gives .Count as string
{{ inc .Count }} // type mismatch

// after
// func: func(v any) (string, error) that parses/converts
{{ inc .Count }}
// or ensure .Count is int in the data model before render
Defensive patterns

Strategy: type-guard

Validate before calling

func coerce(v any, t reflect.Type) (any, error) {
    rv := reflect.ValueOf(v)
    if !rv.IsValid() { return nil, fmt.Errorf("nil value") }
    if !rv.Type().AssignableTo(t) {
        return nil, fmt.Errorf("%T not assignable to %s", v, t)
    }
    return v, nil
}

Type guard

func matchesType(v any, t reflect.Type) bool {
    rv := reflect.ValueOf(v)
    return rv.IsValid() && rv.Type().AssignableTo(t)
}

Try / catch

if err := t.Execute(w, data); err != nil {
    if strings.Contains(err.Error(), "value has type") {
        // normalize data types (e.g. strconv) and retry
        data = normalizeTypes(data)
        err = t.Execute(w, data)
    }
}

Prevention

When it happens

Trigger: Passing a string where an int is expected (or vice versa) to a typed template func/method; indexing a map whose key type doesn't match the provided key; calling via the call builtin with mismatched arg types.

Common situations: FuncMap func with a concrete param type receiving a differently-typed template value; map key typed as int but template passes a string from URL params; refactoring a struct field's type without updating templates.

Related errors


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