gohugoio/hugo · error

symdiff: failed to convert value

Error message

symdiff: failed to convert value: %w

What it means

Wrapping error from SymDiff when convertValue fails while converting an element to the result slice's element type. The %w verb wraps the underlying convertValue error (which may itself be the 'is not assignable' or 'unable to convert' message). This is the user-facing surface for element-coercion failures during symmetric difference computation.

Solutions

  1. Read the wrapped error to find the exact conversion failure (assignable vs numeric).
  2. Normalize both slices to the same element type before calling symdiff.
  3. Map elements to strings or numbers upstream.
  4. Verify element types match across all data sources.

Example fix

// before
{{ symdiff $stringSlice $intSlice }}
// after
{{ symdiff $stringSliceA $stringSliceB }}
Defensive patterns

Strategy: try-catch

Validate before calling

func symdiffSafe(a, b any) (any, error) {
    ta := reflect.TypeOf(a); tb := reflect.TypeOf(b)
    if ta == nil || tb == nil { return nil, errors.New("nil operand") }
    if ta.Kind() != reflect.Slice && ta.Kind() != reflect.Array { return nil, fmt.Errorf("a must be slice/array") }
    if tb.Kind() != reflect.Slice && tb.Kind() != reflect.Array { return nil, fmt.Errorf("b must be slice/array") }
    if ta.Elem() != tb.Elem() && !elementTypesCompatible(ta.Elem(), tb.Elem()) {
        return nil, fmt.Errorf("element types incompatible: %s vs %s", ta.Elem(), tb.Elem())
    }
    return ns.SymDiff(a, b)
}

Type guard

func symdiffCompatible(a, b any) bool {
    ta, tb := reflect.TypeOf(a), reflect.TypeOf(b)
    if ta == nil || tb == nil { return false }
    if ta.Kind() != reflect.Slice && ta.Kind() != reflect.Array { return false }
    if tb.Kind() != reflect.Slice && tb.Kind() != reflect.Array { return false }
    return ta.Elem() == tb.Elem() || elementTypesCompatible(ta.Elem(), tb.Elem())
}

Try / catch

r, err := ns.SymDiff(s2, s1)
if err != nil {
    // err wraps the conversion failure; unwrap for the root cause
    return nil, fmt.Errorf("symdiff failed: %w", err)
}

Prevention

When it happens

Trigger: Calling `{{ symdiff $a $b }}` where elements of $a and $b cannot be coerced to a common type — e.g. []string vs []int, or slices of incompatible structs. convertValue returns an error inside the SymDiff loop and it is wrapped here.

Common situations: Author assumes two slices are element-compatible when they are not, or data sources produce differently-typed slices (JSON numbers vs strings). Common when one slice comes from front matter and another from a data file.

Related errors


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

Appendix: source

Thrown at tpl/collections/symdiff.go:57

		v := reflect.ValueOf(s)

		switch v.Kind() {
		case reflect.Array, reflect.Slice:
			if i == 0 {
				sliceType := v.Type()
				sliceElemType = sliceType.Elem()
				slice = reflect.MakeSlice(sliceType, 0, 0)
			}

			for i := range v.Len() {
				ev, _ := hreflect.Indirect(v.Index(i))
				key := normalize(ev)

				// Append if the key is not in their intersection.
				if ids1[key] != ids2[key] {
					v, err := convertValue(ev, sliceElemType)
					if err != nil {
						return nil, fmt.Errorf("symdiff: failed to convert value: %w", err)
					}
					slice = reflect.Append(slice, v)
				}
			}
		default:
			return nil, fmt.Errorf("arguments to symdiff must be slices or arrays")
		}
	}

	return slice.Interface(), nil
}

View on GitHub (pinned to 52c9bd7908)