{"record":{"id":"b9ba0aa3c9d1810e","repo":"apache/hadoop","slug":"tuple-is-immutable","errorCode":null,"errorMessage":"Tuple is immutable","messagePattern":"Tuple is immutable","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/functional/Tuples.java","lineNumber":79,"sourceCode":"\n    private Tuple(final K key, final V value) {\n      this.key = key;\n      this.value = value;\n    }\n\n    @Override\n    public K getKey() {\n      return key;\n    }\n\n    @Override\n    public V getValue() {\n      return value;\n    }\n\n    @Override\n    public V setValue(final V value) {\n      throw new UnsupportedOperationException(\"Tuple is immutable\");\n    }\n\n    @Override\n    public String toString() {\n      return \"(\" + key + \", \" + value + ')';\n    }\n\n    @Override\n    public boolean equals(final Object o) {\n      if (this == o) {\n        return true;\n      }\n      if (o == null || getClass() != o.getClass()) {\n        return false;\n      }\n      Tuple<?, ?> tuple = (Tuple<?, ?>) o;\n      return Objects.equals(key, tuple.key) && Objects.equals(value, tuple.value);\n    }","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/util/functional/Tuples.java#L61-L97","documentation":"Tuples.pair(k, v) returns a private immutable Tuple implementing Map.Entry: both fields are final and setValue always throws UnsupportedOperationException. Tuples are value objects - 'changing' one means constructing a new pair, not mutating the old one.","triggerScenarios":"Calling entry.setValue(v) on anything returned by Tuples.pair(); passing tuples to generic Map.Entry utilities that remap values in place (entry-stream transforms, merge loops, mutation of List<Map.Entry>); swapping a mutable Pair implementation for Tuples in existing code.","commonSituations":"Refactors away from mutable entry types (AbstractMap.SimpleEntry, a custom Pair with setters); generic library code that accepts Map.Entry and mutates it; in-place update loops ported from code that used a mutable pair.","solutions":["Replace mutation with construction: Tuples.pair(e.getKey(), newValue)","If in-place mutation is genuinely required, build entries with new AbstractMap.SimpleEntry<>(k, v), which supports setValue","Audit shared Map.Entry utilities for setValue calls before feeding them tuples"],"exampleFix":"// before\nfor (Map.Entry<String,Integer> e : tuples) {\n  e.setValue(e.getValue() + 1); // UnsupportedOperationException: Tuple is immutable\n}\n\n// after: build new tuples\nList<Map.Entry<String,Integer>> out = new ArrayList<>();\nfor (Map.Entry<String,Integer> e : tuples) {\n  out.add(Tuples.pair(e.getKey(), e.getValue() + 1));\n}\n// or, when mutation is required:\nMap.Entry<String,Integer> mutable = new AbstractMap.SimpleEntry<>(k, v);","handlingStrategy":"fallback","validationCode":null,"typeGuard":"static boolean isImmutableHadoopTuple(Object o) {\n  // Tuple is private; identify by name before attempting any Map.Entry mutation\n  return o != null && \"org.apache.hadoop.util.functional.Tuples$Tuple\".equals(o.getClass().getName());\n}","tryCatchPattern":null,"preventionTips":["Never call setValue on entries you did not construct - assume foreign Map.Entry objects are immutable","When you need mutation, copy into new AbstractMap.SimpleEntry<>(e.getKey(), e.getValue()) at the boundary","Keep a lint/grep pass for '.setValue(' in code that handles Map.Entry from public APIs"],"tags":["hadoop","java","immutability","map-entry","tuples"],"backgroundTag":"immutable-collection-mutation","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}