{"record":{"id":"2aa2a410e4f2591f","repo":"libgdx/libgdx","slug":"indexoutofboundsexception-2aa2a4","errorCode":null,"errorMessage":"IndexOutOfBoundsException","messagePattern":"IndexOutOfBoundsException","errorType":"exception","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"warning","filePath":"backends/gdx-backends-gwt/src/com/badlogic/gdx/backends/gwt/emu/java/nio/ReadOnlyCharArrayBuffer.java","lineNumber":88,"sourceCode":"\tpublic CharBuffer put (char c) {\n\t\tthrow new ReadOnlyBufferException();\n\t}\n\n\tpublic CharBuffer put (int index, char c) {\n\t\tthrow new ReadOnlyBufferException();\n\t}\n\n\tpublic final CharBuffer put (char[] src, int off, int len) {\n\t\tthrow new ReadOnlyBufferException();\n\t}\n\n\tpublic final CharBuffer put (CharBuffer src) {\n\t\tthrow new ReadOnlyBufferException();\n\t}\n\n\tpublic CharBuffer put (String src, int start, int end) {\n\t\tif ((start < 0) || (end < 0) || (long)start + (long)end > src.length()) {\n\t\t\tthrow new IndexOutOfBoundsException();\n\t\t}\n\t\tthrow new ReadOnlyBufferException();\n\t}\n\n\tpublic CharBuffer slice () {\n\t\treturn new ReadOnlyCharArrayBuffer(remaining(), backingArray, offset + position);\n\t}\n}\n","sourceCodeStart":70,"sourceCodeEnd":97,"githubUrl":"https://github.com/libgdx/libgdx/blob/97f40861878058087be0685ca167ddfde132134b/backends/gdx-backends-gwt/src/com/badlogic/gdx/backends/gwt/emu/java/nio/ReadOnlyCharArrayBuffer.java#L70-L97","documentation":"put(String src, int start, int end) at lines 86-91 validates its arguments BEFORE checking read-only-ness: negative start/end or (per this Harmony-derived check) start+end exceeding src.length() throws IndexOutOfBoundsException at line 88. Only after passing the bounds check does the method throw ReadOnlyBufferException at line 90. So this IndexOutOfBoundsException means the substring range you asked to write is itself invalid, independent of buffer mutability. (Note the check `start + end > src.length()` is the classic Harmony formulation; pass start=0 and end=substring length to stay inside it.)","triggerScenarios":"Calling put(str, start, end) with start or end negative, or a start+end pair whose sum exceeds str.length(), on a read-only CharBuffer in the GWT emu. Example: put(text, offset, offset + count) where offset+count > text.length(), or reversed/zeroed ranges with negative values.","commonSituations":"Substring-copy loops ported from desktop code where the caller computed the end index against a different string than the one passed; off-by-one in offset+count arithmetic when draining a reader into a buffer; negative indices from a preceding calculation that returned -1 as an error sentinel.","solutions":["Clamp/validate the range before the call: if (start < 0 || end < 0 || start + end > src.length()) throw new IllegalArgumentException(\"bad range\") with a descriptive message","Fix the arithmetic: the end parameter here is a LENGTH paired with start, so pass put(str, 0, str.length()) for the whole string","Check for -1 sentinels from index lookup (indexOf etc.) before using them as start/end"],"exampleFix":"// before\nbuf.put(text, offset, offset + count); // offset+count can exceed text.length()\n\n// after\nint end = Math.min(offset + count, text.length());\nif (offset >= 0 && end >= 0 && offset + end <= text.length()) buf.put(text, offset, end - offset);","handlingStrategy":"validation","validationCode":"static void checkRange(String s, int start, int end) {\n  if (start < 0 || end < 0 || (long) start + (long) end > s.length())\n    throw new IllegalArgumentException(\"range [\" + start + \",\" + end + \") invalid for length \" + s.length());\n}\n// call before buf.put(s, start, end)","typeGuard":"boolean isValidStringRange(String s, int start, int end) { return s != null && start >= 0 && end >= 0 && start + end <= s.length(); }","tryCatchPattern":"try { buf.put(str, start, end); } catch (IndexOutOfBoundsException e) { throw new IllegalArgumentException(\"bad substring range \" + start + \"/\" + end + \" for length \" + str.length(), e); }","preventionTips":["Remember this emu treats 'end' as a length added to start: pass (0, s.length()) for the whole string","Never feed indexOf() results (-1 sentinel) directly as range arguments","Clamp computed end indices with Math.min before the call"],"tags":["gwt","nio","charbuffer","index-out-of-bounds","argument-validation","libgdx"],"backgroundTag":null,"analyzedSha":"97f40861878058087be0685ca167ddfde132134b","analyzedAt":"2026-08-14T10:52:53.492Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}