{"record":{"id":"881d6828982a74b2","repo":"oracle/graal","slug":"cannot-modify-the-always-empty-set","errorCode":null,"errorMessage":"Cannot modify the always-empty set","messagePattern":"Cannot modify the always-empty set","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdk/src/org.graalvm.collections/src/org/graalvm/collections/EmptySet.java","lineNumber":53,"sourceCode":" * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\npackage org.graalvm.collections;\n\nimport java.util.Iterator;\n\n/**\n * Singleton instance for empty set. Reuses empty iterator from {@link EmptyMap}.\n */\nclass EmptySet {\n    static final EconomicSet<Object> EMPTY_SET = new EconomicSet<>() {\n        @Override\n        public boolean add(Object element) {\n            EconomicMapImpl.checkNonNull(element);\n            throw new IllegalArgumentException(\"Cannot modify the always-empty set\");\n        }\n\n        @Override\n        public void remove(Object element) {\n            EconomicMapImpl.checkNonNull(element);\n            throw new IllegalArgumentException(\"Cannot modify the always-empty set\");\n        }\n\n        @Override\n        public void clear() {\n            throw new IllegalArgumentException(\"Cannot modify the always-empty set\");\n        }\n\n        @Override\n        public boolean contains(Object element) {\n            EconomicMapImpl.checkNonNull(element);\n            return false;\n        }","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/sdk/src/org.graalvm.collections/src/org/graalvm/collections/EmptySet.java#L35-L71","documentation":"EconomicSet.createSet() with initial capacity 0 returns the shared immutable singleton EmptySet.EMPTY_SET; add(element) on it throws IllegalArgumentException('Cannot modify the always-empty set'). checkNonNull(element) runs first, so a null element throws UnsupportedOperationException instead. The singleton is immutable by design so accidental inserts fail fast.","triggerScenarios":"Calling add() on the set returned by EconomicSet.createSet(0) or EconomicSet.create(EconomicSet) from an empty source — both hand back the EMPTY_SET singleton rather than a growable set.","commonSituations":"Creating a set sized from another collection that happens to be empty (createSet(other.size())); dedup buffers initialized lazily with capacity from a variable that computes to 0; code ported from java.util.HashSet where add on an empty set works.","solutions":["Allocate with positive capacity — EconomicSet.createSet(1) or the no-capacity overload — whenever the set will receive elements.","Before adding, ensure you did not capture the singleton: never store the result of createSet(0) as a mutable accumulator.","If emptiness is data-dependent, compute capacity as Math.max(1, expectedSize)."],"exampleFix":"// before\nEconomicSet<T> s = EconomicSet.createSet(source.size()); // source empty -> singleton\ns.add(item); // throws\n\n// after\nEconomicSet<T> s = EconomicSet.createSet(Math.max(1, source.size()));\ns.add(item);","handlingStrategy":"validation","validationCode":"EconomicSet<T> s = EconomicSet.createSet(Math.max(1, expectedSize)); // growable even when expectedSize == 0","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never use createSet(0) for accumulators.","Clamp computed capacities to at least 1.","Treat the empty singleton as read-only by contract."],"tags":["graalvm","collections","immutability","economic-set"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}