{"record":{"id":"aa69e477af9f809b","repo":"semaphoreui/semaphore","slug":"expected-map-for-field-s-but-got-t","errorCode":null,"errorMessage":"expected map for field %s but got %T","messagePattern":"expected map for field (.+?) but got %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/config.go","lineNumber":1253,"sourceCode":"\t\t\t\t\t\t\t\t\treturn fmt.Errorf(\"cannot assign element of type %s to slice element of type %s\", srcElemVal.Type(), fieldElemType)\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tdstElem = reflect.ValueOf(newVal)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tnewSlice = reflect.Append(newSlice, dstElem)\n\t\t\t\t\t}\n\n\t\t\t\t\tfieldValue.Set(newSlice)\n\t\t\t\tcase reflect.Map:\n\t\t\t\t\tif fieldValue.IsNil() {\n\t\t\t\t\t\tmapValue := reflect.MakeMap(fieldValue.Type())\n\t\t\t\t\t\tfieldValue.Set(mapValue)\n\t\t\t\t\t}\n\n\t\t\t\t\t// Handle map\n\t\t\t\t\tif val.Kind() != reflect.Map {\n\t\t\t\t\t\treturn fmt.Errorf(\"expected map for field %s but got %T\", field.Name, value)\n\t\t\t\t\t}\n\n\t\t\t\t\tfor _, key := range val.MapKeys() {\n\t\t\t\t\t\tmapElemValue := val.MapIndex(key)\n\t\t\t\t\t\tmapElemType := fieldValue.Type().Elem()\n\n\t\t\t\t\t\tsrcVal := fieldValue.MapIndex(key)\n\t\t\t\t\t\tvar mapElem reflect.Value\n\t\t\t\t\t\tif srcVal.IsValid() {\n\t\t\t\t\t\t\tmapElem = cloneStruct(srcVal)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmapElem = reflect.New(mapElemType).Elem()\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif mapElemType.Kind() == reflect.Struct {\n\t\t\t\t\t\t\tif err := assignMapToStructRecursive(mapElemValue.Interface().(map[string]any), mapElem); err != nil {\n\t\t\t\t\t\t\t\treturn err\n\t\t\t\t\t\t\t}","sourceCodeStart":1235,"sourceCodeEnd":1271,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/util/config.go#L1235-L1271","documentation":"For map-typed struct fields, the assigned value must itself be a Go map. If the value under the matching JSON key is any other kind (string, int, slice, bool), this error is returned. Unlike the struct-field case, a JSON-array-style string is not parsed here — the value must already be a map.","triggerScenarios":"Assigning m[\"db\"] = \"host=localhost\" (a string) or a slice to a field of type map[string]X via AssignMapToStruct.","commonSituations":"Env-var-driven config where a map was flattened to a delimited string; config schema changed a field from scalar/slice to map; hand-built maps where the wrong key received a scalar.","solutions":["Supply a real map in the source: map[string]any{\"host\": \"localhost\"}.","If the value is a JSON object string, json.Unmarshal it into map[string]any before assignment.","Verify the config key and struct field type agree — change one so the shapes match.","For env-sourced maps, parse key=value pairs into a map yourself before calling AssignMapToStruct."],"exampleFix":"// before\nm := map[string]any{\"db\": \"host=localhost\"} // field is map[string]any\n// after\nm := map[string]any{\"db\": map[string]any{\"host\": \"localhost\"}}","handlingStrategy":"type-guard","validationCode":"if v, ok := m[\"db\"]; ok {\n  if _, isMap := v.(map[string]any); !isMap {\n    return fmt.Errorf(\"db must be an object, got %T\", v)\n  }\n}","typeGuard":"func isMapValue(v any) bool {\n  rv := reflect.ValueOf(v)\n  return rv.Kind() == reflect.Map\n}","tryCatchPattern":"if err := util.AssignMapToStruct(m, &cfg); err != nil {\n  if strings.Contains(err.Error(), \"expected map for field\") {\n    log.Fatalf(\"map field requires object value: %v\", err)\n  }\n}","preventionTips":["Supply nested config as objects, not delimited strings or lists.","If values arrive as JSON object strings, unmarshal to map[string]any first.","Sync flattened env-var config with the map-shaped struct fields explicitly."],"tags":["reflection","config","go","map"],"backgroundTag":"config-type-mismatch","analyzedSha":"1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa","analyzedAt":"2026-09-07T11:00:33.293Z","contentChangedAt":"2026-09-07T11:00:33.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}