{"record":{"id":"1e387b1a445d49b6","repo":"DapperLib/Dapper","slug":"an-item-with-the-same-key-has-already-been-added","errorCode":null,"errorMessage":"An item with the same key has already been added","messagePattern":"An item with the same key has already been added","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Dapper/SqlMapper.DapperRow.cs","lineNumber":182,"sourceCode":"            }\r\n\r\n            public object? SetValue(string key, object? value)\r\n            {\r\n                return SetValue(key, value, false);\r\n            }\r\n\r\n            private object? SetValue(string key, object? value, bool isAdd)\r\n            {\r\n                if (key is null) throw new ArgumentNullException(nameof(key));\r\n                int index = table.IndexOfName(key);\r\n                if (index < 0)\r\n                {\r\n                    index = table.AddField(key);\r\n                }\r\n                else if (isAdd && index < values.Length && !(values[index] is DeadValue))\r\n                {\r\n                    // then semantically, this value already exists\r\n                    throw new ArgumentException(\"An item with the same key has already been added\", nameof(key));\r\n                }\r\n                return SetValue(index, value);\r\n            }\r\n            internal object? SetValue(int index, object? value)\r\n            {\r\n                int oldLength = values.Length;\r\n                if (oldLength <= index)\r\n                {\r\n                    // we'll assume they're doing lots of things, and\r\n                    // grow it to the full width of the table\r\n                    Array.Resize(ref values, table.FieldCount);\r\n                    for (int i = oldLength; i < values.Length; i++)\r\n                    {\r\n                        values[i] = DeadValue.Default;\r\n                    }\r\n                }\r\n                return values[index] = value;\r\n            }\r","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/DapperLib/Dapper/blob/72a54c475f75e18cb93cba0809d00a5e6e49efd9/Dapper/SqlMapper.DapperRow.cs#L164-L200","documentation":"DapperRow implements IDictionary<string,object?>. Its private SetValue(key, value, isAdd) enforces add-semantics: when isAdd is true and the key already maps to a live (non-DeadValue) slot, it throws ArgumentException. The public path is IDictionary<string,object?>.Add, which calls SetValue(key, value, true) at SqlMapper.DapperRow.cs:147. This mirrors Dictionary<TKey,TValue>.Add rejecting duplicate keys.","triggerScenarios":"Cast a Dapper query result (dynamic or the underlying DapperRow) to IDictionary<string,object?> and call .Add(existingColumn, value); or use ICollection<KeyValuePair>.Add which forwards to IDictionary.Add. Only the Add path sets isAdd=true; the indexer setter (this[key]=value) and public SetValue use isAdd=false and never throw.","commonSituations":"Materializing a row then injecting extra computed columns via dictionary Add instead of the indexer; porting ExpandoObject/Dictionary code that assumed overwrite; queries returning two columns with the same name so the second already occupies a slot when re-added.","solutions":["Use the indexer to overwrite: ((IDictionary<string,object?>)row)[key] = value; — it calls SetValue with isAdd=false and never throws on duplicates.","Guard with ContainsKey before Add: if (!dic.ContainsKey(key)) dic.Add(key, value);","Remove then Add when you need strict add semantics: dic.Remove(key); dic.Add(key, value);","If you need overwrite-everywhere semantics, copy the DapperRow into a new Dictionary<string,object?> and manipulate that."],"exampleFix":"// before\nvar dic = (IDictionary<string, object?>)row;\ndic.Add(\"Id\", 42); // throws if Id column already present\n\n// after\nvar dic = (IDictionary<string, object?>)row;\ndic[\"Id\"] = 42; // indexer: overwrite, never throws","handlingStrategy":"validation","validationCode":"IDictionary<string, object?> dic = (IDictionary<string, object?>)row;\nif (dic.ContainsKey(key)) throw new InvalidOperationException($\"Key already present: {key}\");\ndic.Add(key, value);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer the indexer dic[key] = value over Add unless you genuinely need add-or-fail semantics.","If porting Dictionary/ExpandoObject code, audit every .Add call against the row's column set.","When projecting extra columns, copy the DapperRow into a new Dictionary and add freely."],"tags":["dapper","dapperrow","dictionary","duplicate-key","argumentexception"],"backgroundTag":null,"analyzedSha":"72a54c475f75e18cb93cba0809d00a5e6e49efd9","analyzedAt":"2026-08-13T14:18:18.115Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}