semaphoreui/semaphore · error

cannot assign element of type

Error message

cannot assign element of type %s to slice element of type %s

What it means

For slice-of-struct fields, if the source element is not a map, the reflector tries reflect Convertibility to the struct element type; a scalar that is not directly convertible to the struct type (which scalars never are) hits this error. It means a non-map, non-convertible value was given where a struct element (or its map form) was expected.

Solutions

  1. Supply each element as map[string]any matching the struct's JSON keys, e.g. [{"name": "web-1"}].
  2. Change the struct field to a slice of the scalar type if the data is genuinely scalar.
  3. Pre-convert scalar elements into struct values yourself before calling AssignMapToStruct.
  4. Check the field's json/db tags to confirm the config key maps to the intended slice field.

Example fix

// before
m := map[string]any{"servers": []any{"web-1"}} // field is []Server
// after
m := map[string]any{"servers": []any{map[string]any{"name": "web-1"}}}
Defensive patterns

Strategy: validation

Validate before calling

for _, e := range elems.([]any) {
  if _, ok := e.(map[string]any); !ok {
    return fmt.Errorf("struct slice needs object elements, got %T", e)
  }
}

Type guard

func isObjectElement(e any) bool {
  _, ok := e.(map[string]any)
  return ok
}

Try / catch

defer func() {
  if err := util.AssignMapToStruct(m, &cfg); err != nil {
    log.Fatalf("config assignment failed: %v", err)
  }
}()

Prevention

When it happens

Trigger: Assigning []any{"web-1", 42} to a []SomeStruct field via AssignMapToStruct — string/int elements cannot convert to a struct type.

Common situations: Config lists of names/IDs mapped onto a []struct field that expects objects (e.g. [{"name": ...}]); a schema change turned struct elements into plain identifiers; copy-paste error in the map keys.

Related errors


AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07). Data as JSON: /api/errors/415ba1b02c6b35bb. Report an issue: GitHub.

Appendix: source

Thrown at util/config.go:1226

						}

						var dstElem reflect.Value
						// Prepare destination element
						if fieldElemType.Kind() == reflect.Struct {
							dstElem = reflect.New(fieldElemType).Elem()
							if srcElemVal.Kind() == reflect.Map {
								// Expect map[string]any
								mIface, ok := srcElemVal.Interface().(map[string]any)
								if !ok {
									return fmt.Errorf("cannot assign element of type %T to slice element of type %s", srcElemVal.Interface(), fieldElemType)
								}
								if err := assignMapToStructRecursive(mIface, dstElem); err != nil {
									return err
								}
							} else if srcElemVal.Type().ConvertibleTo(fieldElemType) {
								dstElem = srcElemVal.Convert(fieldElemType)
							} else {
								return fmt.Errorf("cannot assign element of type %s to slice element of type %s", srcElemVal.Type(), fieldElemType)
							}
						} else {
							// Primitive or other kinds
							if srcElemVal.Type().ConvertibleTo(fieldElemType) {
								dstElem = srcElemVal.Convert(fieldElemType)
							} else {
								newVal, converted := CastValueToKind(srcElemVal.Interface(), fieldElemType.Kind())
								if !converted {
									return fmt.Errorf("cannot assign element of type %s to slice element of type %s", srcElemVal.Type(), fieldElemType)
								}
								dstElem = reflect.ValueOf(newVal)
							}
						}

						newSlice = reflect.Append(newSlice, dstElem)
					}

					fieldValue.Set(newSlice)

View on GitHub (pinned to 1774ccb71a)