'Either zero or 2 or more [DropdownMenuItem]s were detected with the same value

I am new to Flutter but I am trying to create a DropdownButtonFormField and it is not working. I am getting an error that says I have duplicate values. What is interesting is that I do not have a list with duplicate values. I have found a similar question on SO and the solution says to initiate the strings with a value and that the user was duplicating a list item, but I have a similar solution for another another list and it seems to work fine. I cannot figure out why it is not working here. Any help is greatly appreciated.

Error Message:

There should be exactly one item with [DropdownButton]'s value: 0. 
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:flutter/src/material/dropdown.dart':
Failed assertion: line 1411 pos 15: 'items == null || items.isEmpty || value == null ||
              items.where((DropdownMenuItem<T> item) {
                return item.value == value;
              }).length == 1'
The relevant error-causing widget was: 
  StreamBuilder<UserProfile>

ProfileForm Class:

final List<String> accountType = ['Educator', 'School Administrator', 'Parent'];

  String _currentAccountType;

  @override
  Widget build(BuildContext context) {
    final user = Provider.of<User>(context);
    return StreamBuilder<UserProfile>(
        stream: DatabaseService(uid: user.uid).userProfileData,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            UserProfile userProfileData = snapshot.data;
            return Form(
              key: _formKey,
              child: Column(
                children: <Widget>[
                  SizedBox(height: 20.0),
                  DropdownButtonFormField(
                    decoration: textInputDecoration,
                    value: _currentAccountType ?? userProfileData.accountType,
                    items: accountType.map((accountType) {
                      return DropdownMenuItem(
                        value: accountType,
                        child: Text(accountType),
                      );
                    }).toList(),
                    onChanged: (val) {
                      setState(() {
                        _currentAccountType = val;
                      });
                    },
                  ),

Database Class

class DatabaseService {
  final String uid;
  DatabaseService({this.uid});

  final CollectionReference userProfileCollection =
      Firestore.instance.collection('user_profile');

  Future updateUserProfile(
      String accountType,
      String birthDate,
      String courseName,
      String dateJoined,
      String email,
      String firstName,
      String lastName,
      String schoolName,
      String title) async {
    return await userProfileCollection.document(uid).setData({
      'accountType': accountType,
      'birthDate': birthDate,
      'courseName': courseName,
      'dateJoined': dateJoined,
      'email': email,
      'firstName': firstName,
      'lastName': lastName,
      'schoolName': schoolName,
      'title': title,
    });
  }

  //User Profile from snapshot
  List<Profile> _userProfileListFromSnapshot(QuerySnapshot snapshot) {
    return snapshot.documents.map((doc) {
      return Profile(
        accountType: doc.data['accountType'] ?? '',
        birthDate: doc.data['birthDate'] ?? '',
        courseName: doc.data['courseName'] ?? '',
        dateJoined: doc.data['dateJoined'] ?? '',
        email: doc.data['email'] ?? '',
        firstName: doc.data['firstName'] ?? '',
        lastName: doc.data['lastName'] ?? '',
        schoolName: doc.data['schoolName'] ?? '',
        title: doc.data['title'] ?? '',
      );
    }).toList();
  }

  UserProfile _userProfileFromSnapshot(DocumentSnapshot snapshot) {
    return UserProfile(
      uid: uid,
      accountType: snapshot.data['accountType'],
      birthDate: snapshot.data['birthDate'],
      courseName: snapshot.data['courseName'],
      dateJoined: snapshot.data['dateJoined'],
      email: snapshot.data['email'],
      firstName: snapshot.data['firstName'],
      lastName: snapshot.data['lastName'],
      schoolName: snapshot.data['schoolName'],
      title: snapshot.data['title'],
    );
  }

  Stream<List<Profile>> get userProfile {
    return userProfileCollection.snapshots().map(_userProfileListFromSnapshot);
  }

  Stream<UserProfile> get userProfileData {
    return userProfileCollection
        .document(uid)
        .snapshots()
        .map(_userProfileFromSnapshot);
  }
}


Solution 1:[1]

userProfileData.accountType is '0', not 'Educator' or 'School Administrator' or 'Parent'.

Success: value must in items.value

 final List<String> accountType = ['Educator', 'School Administrator', 'Parent'];

 DropdownButtonFormField(
                    decoration: textInputDecoration,
                    value: accountType[0],
                    items: accountType.map((accountType) {
                      return DropdownMenuItem(
                        value: accountType,
                        child: Text(accountType),
                      );
                    }).toList(),
                    onChanged: (val) {
                      setState(() {
                        _currentAccountType = val;
                      });
                    },
                  ),

Failed: There should be exactly one item with [DropdownButton]'s value: hahaha

 final List<String> accountType = ['Educator', 'School Administrator', 'Parent'];

 DropdownButtonFormField(
                    decoration: textInputDecoration,
                    value: 'hahaha',
                    items: accountType.map((accountType) {
                      return DropdownMenuItem(
                        value: accountType,
                        child: Text(accountType),
                      );
                    }).toList(),
                    onChanged: (val) {
                      setState(() {
                        _currentAccountType = val;
                      });
                    },
                  ),

Solution 2:[2]

It seems that there is some clash when using 'hint:' and 'value:' simultaneously. My approach was to add a global _selected in the Widget's State:

bool _selected;

and then in the DropdownButton itself:

value: _selected ? _userChoice: null,

In this way you actually use one of the item values once they are set.

Here is an entire example taken from some traning code (excuse the silliness ;)

class FavoriteCity extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _FavoriteCityState();
  }
}

class _FavoriteCityState extends State<FavoriteCity> {
  String nameCity = '';
  String _loveLevel = '';
  bool _selected = false;
  var _howMuchLoved = ['A little', 'So so', 'Quite a bit', 'A lot', 'Greatly'];

  @override
  Widget build(BuildContext context) {
    print('Widget Built');
    return Scaffold(
      appBar: AppBar(
        title: Text('Favorite city app'),
        elevation: 8.0,
      ),
      body: Container(
        margin: EdgeInsets.all(20.0),
        child: Column(
          children: <Widget>[
            TextField(
              onSubmitted: (String userInput) {
                setState(() {
                  print('State rebuilt');
                  nameCity = userInput;
                });
              },
            ),
            DropdownButton<String>(
              hint: Text('How much do you love the city?'),
              items: _howMuchLoved.map((String myMenuItem) {
                return DropdownMenuItem<String>(
                  value: myMenuItem,
                  child: Text(myMenuItem),
                );
              }).toList(),
              onChanged: (String valueSelectedByUser) {
                _dropDownItemSelected(valueSelectedByUser);
              },
              value: _selected ? _loveLevel : null,
              isDense: true,
            ),
            Padding(
              padding: EdgeInsets.all(20.0),
              child: Text(
                'Your favorite city is $nameCity ! \n ... and you love it $_loveLevel',
                style: TextStyle(
                  fontSize: 20.0,
                  fontStyle: FontStyle.italic,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  void _dropDownItemSelected(String valueSelectedByUser) {
    setState(() {
      this._loveLevel = valueSelectedByUser;
      _selected = true;
    });
  }

Solution 3:[3]

In my case, below change resolved the error:

Error scenario:

var itemList=['Alpha','Beta','Cat'];
var itemSelected='Zebra';

Working scenario:

var itemList=['Alpha','Beta','Cat'];
var itemSelected='Cat'; //Can be Alpha, Beta or Cat but not any other value

Dropdown widget code:

DropdownButton<String>(
                    items: itemList.map((String singleItem){
                          return DropdownMenuItem<String>(
                            value: singleItem,
                            child:Text(singleItem)
                          );
                    }).toList(),

                    onChanged: (String itemChosen){
                      setState(() {
                        this.itemSelected=itemChosen;
                      });
                    },
                   value:itemSelected ,

                  ),

Having the 'itemSelected' variable value same as one of the elements in the list resolved the problem for me.

Solution 4:[4]

I also encountered this case, but there is no workaround for you to help me see where the error code is?

var dataLv2 = new List<DropdownMenuItem<String>>();
var dataLv3 = new List<DropdownMenuItem<String>>();

Widget widgetLoaiViPham() {
    return StreamBuilder(
      initialData: "KHONG",
      stream: widget.bloc.subject_ketluan_cmis_loai_vipham_stream,
      builder: (context, snapshot) {
        return DropdownButtonFormField(
          value: snapshot.data,
          items: getDropDownMenuLv1(),
          decoration: InputDecoration(labelText: "Lo?i vi ph?m"),
          onChanged: (newVal) {
            dataLv2 = defaultVal2(newVal);
            var tempVal2 = dataLv2.length > 0 ? dataLv2.first.value : null;
            dataLv3 = defaultVal3(tempVal2);
            var tempVal3 = dataLv3.length > 0 ? dataLv3.first.value : null;

            widget.bloc.subject_ketluan_cmis_loai_vipham_sink.add(newVal);
            widget.bloc.subject_ketluan_cmis_loai_kiemtra_sink.add(tempVal2);
            widget.bloc.subject_ketluan_cmis_loai_xuly_sink.add(tempVal3);
          },
        );
      },
    );
}

Widget widgetLoaiKiemTra() {
    return StreamBuilder(
      initialData: null,
      stream: widget.bloc.subject_ketluan_cmis_loai_kiemtra_stream,
      builder: (context, snapshot) {
        return DropdownButtonFormField(
          value: null,
          items: dataLv2,
          decoration: InputDecoration(labelText: "Lo?i ki?m tra"),
          onChanged: (newVal) {
            dataLv3 = defaultVal3(newVal);
            var tempVal3 = dataLv3.length > 0 ? dataLv3.first.value : null;

            widget.bloc.subject_ketluan_cmis_loai_kiemtra_sink.add(newVal);
            widget.bloc.subject_ketluan_cmis_loai_xuly_sink.add(tempVal3);
          },
        );
      },
    );
}

When changing the widgetLoaiViPham, the data of the widgetLoaiKiemTra will change according to everything is normal, but when I change the widgetLoaiKiemTra and then I continue to change the widgetLoaiViPham, an error will occur.

Although debugging, the value and items of widgetLoaiKiemTra match

Solution 5:[5]

In my case: my list had duplicated data which presents me with this error, idk know it gets duplicated along the way in my app, so before displaying the dropdown button I just cleared my list and refill the list before passing it onto dropdown. if this type of error occurs, crosscheck this solution too.

Solution 6:[6]

Ended up here after facing the same issue with a Dropdown list of custom objects, even though the populated list did not contain any duplicates (in terms of data).

The resolution for me was to override the == operator and hashCode function in the class of the aforementioned objects.

Example (omitted some irrelevant internal functions for higher visibility):

import 'dart:convert';
import 'package:quiver/core.dart';

class PrefectureDto{
  String id = ""; // Every prefecture is given a unique id from the DEDDHE API. This id is used for the requests.
  String name = ""; // The name of each prefecture.

  /// Constructor that sets all the fields of the Prefecture model.
  PrefectureDto(this.id, this.name);

  ...internal methods etc...

  @override
  bool operator ==(Object other){
    PrefectureDto o = other as PrefectureDto;
    if(o.id == id) return true;
    return false;
  }

  @override
  int get hashCode => hash2(id.hashCode, name.hashCode);
}

Implementation of the dropdown, for keeping my answer consistent:

class _PrefecturesDropdownState extends State<PrefecturesDropdown> {
  late PrefectureDto defaultPrefecture;
  List<PrefectureDto> prefectures = List<PrefectureDto>.empty(growable: true);
  late final Future? prefecturesFuture = _getPrefectures();

  /// Performs a request to the DEDDHE website and extracts
  /// the prefectures from the HTML.
  Future<List<PrefectureDto>> _getPrefectures() async {
    Response response = (await Rest.doGET(
        "URL", {}));

    setState(() {
      if (prefectures.isEmpty){
        prefectures = PrefecturesHandler.extract(response.body);
      }
      defaultPrefecture = prefectures.firstWhere((element) => element.id == "10");
    });
    return prefectures;
  }

  Widget prefecturesDropdown(BuildContext context) {
    return DropdownButton<PrefectureDto>(
      value: defaultPrefecture,
      icon: const Icon(Icons.keyboard_arrow_down),
      elevation: 16,
      style: const TextStyle(color: Colors.black),
      underline: Container(
        height: 2,
        color: const Color(0xFFB00020),
      ),
      onChanged: (PrefectureDto? newValue) {
        setState(() {
          defaultPrefecture = newValue!;
        });
      },
      items: prefectures.map<DropdownMenuItem<PrefectureDto>>((PrefectureDto value) {
        return DropdownMenuItem<PrefectureDto>(
          value: value,
          child: Text(value.name),
        );
      }).toList(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: prefecturesFuture,
        builder: (context, snapshot) {
            return prefecturesDropdown(context);
        });
  }
}

Full code on GitHub

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 NBM
Solution 4 LĂȘ V?n ???c
Solution 5 Anas Yousuf
Solution 6 Ioannis Brant-Ioannidis