gohugoio/hugo · error

arg %d: %w

Error message

arg %d: %w

What it means

Raised by the `call` action when `prepareArg` fails to coerce argument `i` to the function's declared parameter type (funcs.go:347-348). The underlying error (nil-mismatch or wrong type) is wrapped with the arg position. Causes: passing nil to a non-nillable param, or a value whose type is not assignable/convertible.

Source

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

		}
		dddType = typ.In(numIn - 1).Elem()
	} else {
		if len(args) != numIn {
			return reflect.Value{}, fmt.Errorf("wrong number of args for %s: got %d want %d", name, len(args), numIn)
		}
	}
	argv := make([]reflect.Value, len(args))
	for i, arg := range args {
		arg = indirectInterface(arg)
		// Compute the expected type. Clumsy because of variadics.
		argType := dddType
		if !typ.IsVariadic() || i < numIn-1 {
			argType = typ.In(i)
		}

		var err error
		if argv[i], err = prepareArg(arg, argType); err != nil {
			return reflect.Value{}, fmt.Errorf("arg %d: %w", i, err)
		}
	}
	return safeCall(fn, argv)
}

// safeCall runs fun.Call(args), and returns the resulting value and error, if
// any. If the call panics, the panic value is returned as an error.
func safeCall(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) {
	defer func() {
		if r := recover(); r != nil {
			if e, ok := r.(error); ok {
				err = e
			} else {
				err = fmt.Errorf("%v", r)
			}
		}
	}()
	ret := fun.Call(args)

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Convert in-template with the appropriate builtin (e.g. `int`, `string`) before calling.
  2. Make the Go func accept interface{} or loose types and validate inside.
  3. Guard nils: `{{with .V}}{{call .Fn .}}{{end}}`.
  4. Align the call-site argument types to the declared parameter types.

Example fix

// before
{{call .Count "5"}}   // func(int) int

// after
{{call .Count (int "5")}}
Defensive patterns

Strategy: type-guard

Validate before calling

// Coerce arg types before calling:
//   {{call .Count (int .Qty)}}
// Or make the Go func accept interface{} and validate internally.

Type guard

func matchesParam(fn interface{}, idx int, arg interface{}) bool {
    ft := reflect.TypeOf(fn)
    if ft.Kind() != reflect.Func { return false }
    var pt reflect.Type
    if ft.IsVariadic() && idx >= ft.NumIn()-1 {
        pt = ft.In(ft.NumIn()-1).Elem()
    } else {
        pt = ft.In(idx)
    }
    av := reflect.ValueOf(arg)
    if !av.IsValid() { return false }
    return av.Type().AssignableTo(pt)
}

Prevention

When it happens

Trigger: Passing a string to an int param; passing nil to `func(int)`; passing a struct where `*struct` is expected; mixing signed/unsigned ints in a way intLike conversion cannot bridge.

Common situations: FuncMap helpers whose signatures expect concrete types but the template supplies front-matter strings; nil optional values forwarded into typed params; refactoring parameter types.

Related errors


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