gohugoio/hugo · error

%s is not assignable to %s

Error message

%s is not assignable to %s

What it means

Thrown by convertValue when a value cannot be assigned to the target type and the target kind is neither string nor numeric (so neither ToStringValueE nor convertNumber applies). convertValue is used by set operations (e.g. SymDiff) to coerce elements to the result slice's element type. Both the source type and target type are named via %s.

Source

Thrown at tpl/collections/reflect_helpers.go:92

		}
	}

	return seen, nil
}

// We have some different numeric and string types that we try to behave like
// they were the same.
func convertValue(v reflect.Value, to reflect.Type) (reflect.Value, error) {
	if v.Type().AssignableTo(to) {
		return v, nil
	}
	switch kind := to.Kind(); {
	case kind == reflect.String:
		return hreflect.ToStringValueE(v)
	case hreflect.IsNumber(kind):
		return convertNumber(v, to)
	default:
		return reflect.Value{}, fmt.Errorf("%s is not assignable to %s", v.Type(), to)
	}
}

func convertNumber(v reflect.Value, typ reflect.Type) (reflect.Value, error) {
	if v, ok := hreflect.ConvertIfPossible(v, typ); ok {
		return v, nil
	}
	return reflect.Value{}, fmt.Errorf("unable to convert value of type %q to %q", v.Type().String(), typ.String())
}

func newSliceElement(items any) any {
	tp := reflect.TypeOf(items)
	if tp == nil {
		return nil
	}
	switch tp.Kind() {
	case reflect.Array, reflect.Slice:
		tp = tp.Elem()

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Ensure both slices share a compatible element type before calling SymDiff.
  2. Map/transform elements to a common type (string or number) upstream.
  3. Avoid symdiff on slices of custom structs unless their types match.
  4. Inspect both types named in the error to find the incompatibility.

Example fix

// before
{{ symdiff $structSlice $intSlice }}
// after
{{ symdiff $intSliceA $intSliceB }}
Defensive patterns

Strategy: type-guard

Validate before calling

func elementTypesCompatible(a, b reflect.Type) bool {
    if a == b { return true }
    if a.Kind() == reflect.String || b.Kind() == reflect.String { return true }
    if hreflect.IsNumber(a.Kind()) && hreflect.IsNumber(b.Kind()) { return true }
    return a.Kind() == reflect.Interface || b.Kind() == reflect.Interface
}

Type guard

func isConvertibleType(t reflect.Type) bool {
    return t.Kind() == reflect.String || hreflect.IsNumber(t.Kind())
}

Prevention

When it happens

Trigger: SymDiff (or another caller of convertValue) where the two input slices have element types that cannot be reconciled — e.g. symdiff a []struct against []int where the struct isn't string/number-coercible. The default branch of convertValue fires for non-string, non-number target kinds.

Common situations: Mixing slices of incompatible element types in set operations, or evolving a slice's element type during a refactor while old data remains. Less common than the slice/array type errors but arises with heterogeneous structs.

Related errors


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