gohugoio/hugo · error

value is nil; should be of type %s

Error message

value is nil; should be of type %s

What it means

Thrown by prepareArg (used by doIndex for map indexing) when the supplied index value is reflect.Invalid (untyped nil) and the map's key type is not nillable (canBeNil returns false for non-chan/func/interface/map/pointer/slice kinds). A nil index only makes sense for nillable key types; for concrete key types like int or string it is an error naming the expected type via %s.

Source

Thrown at tpl/collections/index.go:126

			}
		case reflect.Invalid:
			// the loop holds invariant: v.IsValid()
			panic("unreachable")
		default:
			return nil, fmt.Errorf("can't index item of type %s", v.Type())
		}
	}
	return v.Interface(), nil
}

// prepareArg checks if value can be used as an argument of type argType, and
// converts an invalid value to appropriate zero if possible.
//
// Copied from Go stdlib src/text/template/funcs.go.
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 reflect.Value{}, fmt.Errorf("value has type %s; should be %s", value.Type(), argType)
	}
	return value, nil
}

// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
//
// Copied from Go stdlib src/text/template/exec.go.
func canBeNil(typ reflect.Type) bool {
	switch typ.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
		return true
	}
	return false

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Default the key before indexing: `{{ $k := default "fallback" $maybeNil }}{{ index $m $k }}`.
  2. Guard with isset/with: `{{ with $maybeNil }}{{ index $m . }}{{ end }}`.
  3. Use a map with a pointer/interface key type if nil keys are legitimate.
  4. Ensure partial callers always pass the key argument.

Example fix

// before
{{ index $stringMap $missingKey }}
// after
{{ with $missingKey }}{{ index $stringMap . }}{{ else }}{{ index $stringMap "default" }}{{ end }}
Defensive patterns

Strategy: validation

Validate before calling

func nonNilMapKey(mapV reflect.Value, key any) (reflect.Value, error) {
    if key == nil || !reflect.ValueOf(key).IsValid() {
        kt := mapV.Type().Key()
        switch kt.Kind() {
        case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
            return reflect.Zero(kt), nil
        default:
            return reflect.Value{}, fmt.Errorf("nil key invalid for map key type %s", kt)
        }
    }
    return reflect.ValueOf(key), nil
}

Type guard

func canKeyBeNil(kt reflect.Type) bool {
    switch kt.Kind() {
    case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: Calling `{{ index $intKeyedMap nil }}` where the map is `map[int]...`, or `{{ index $stringKeyedMap $missing }}` where $missing resolved to untyped nil. prepareArg receives an invalid reflect.Value and the map key type (e.g. string, int) cannot hold nil.

Common situations: A template variable that was never set (defaults to nil) is used as a map key, or optional front matter is nil and passed straight through. Common with optional params in partials where a key may be absent.

Related errors


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