{"record":{"id":"fc7ccb8b0b6fc66c","repo":"mybatis/mybatis-3","slug":"cannot-remove-element-from-cursor","errorCode":null,"errorMessage":"Cannot remove element from Cursor","messagePattern":"Cannot remove element from Cursor","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/cursor/defaults/DefaultCursor.java","lineNumber":222,"sourceCode":"      // Fill next with object fetched from hasNext()\n      T next = object;\n\n      if (!objectWrapperResultHandler.fetched) {\n        next = fetchNextUsingRowBound();\n      }\n\n      if (objectWrapperResultHandler.fetched) {\n        objectWrapperResultHandler.fetched = false;\n        object = null;\n        iteratorIndex++;\n        return next;\n      }\n      throw new NoSuchElementException();\n    }\n\n    @Override\n    public void remove() {\n      throw new UnsupportedOperationException(\"Cannot remove element from Cursor\");\n    }\n  }\n}\n","sourceCodeStart":204,"sourceCodeEnd":226,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/cursor/defaults/DefaultCursor.java#L204-L226","documentation":"The Iterator returned by a MyBatis Cursor is read-only: remove() always throws UnsupportedOperationException. A Cursor streams rows directly from a JDBC ResultSet over an already-executed query, so there is no backing collection from which an element could be removed. This matches the java.util.Iterator contract that makes remove() optional.","triggerScenarios":"Calling cursor.iterator().remove(); using the Cursor in any API that invokes Iterator.remove() (e.g., some collection constructors, Iterator-based removal utilities, or hand-rolled filtering loops that remove rejected items); calling remove() on the Cursor in a while(hasNext())/next() loop.","commonSituations":"Porting List-based iteration code (that used iterator.remove() to filter) to Cursor-based streaming; generic framework code that assumes a mutable iterator; unit tests that exercise remove() on iterators.","solutions":["Do not call remove(); build a filtered output collection instead while streaming","If you need removal semantics, materialize into a List first and use its iterator or removeIf","Filter in SQL (WHERE clause) so unwanted rows are never streamed"],"exampleFix":"// before\nIterator<User> it = cursor.iterator();\nwhile (it.hasNext()) {\n  if (!it.next().isActive()) it.remove(); // UnsupportedOperationException\n}\n\n// after\nList<User> active = new ArrayList<>();\nfor (User u : cursor) {\n  if (u.isActive()) active.add(u);\n}","handlingStrategy":"validation","validationCode":"// Iterator.remove() is never valid on a Cursor;\n// use a filter loop instead of mutation.\nList<User> kept = new ArrayList<>();\nfor (User u : cursor) {\n  if (accept(u)) kept.add(u);\n}","typeGuard":null,"tryCatchPattern":"try {\n  it.remove();\n} catch (UnsupportedOperationException e) {\n  // expected for Cursor: switch to filtered-collection approach\n}","preventionTips":["Filter while streaming into a new collection; never mutate through a Cursor","Push filtering into the SQL WHERE clause when possible","Materialize to List and use removeIf if you truly need removal semantics"],"tags":["mybatis","cursor","iterator","unsupported-operation","streaming"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}