{"record":{"id":"6b317ef9a68635d2","repo":"antlr/antlr4","slug":"replace-range-invalid-from-to-size-size","errorCode":null,"errorMessage":"replace: range invalid: {from}..{to}(size={size})","messagePattern":"replace: range invalid: (.+?)\\.\\.(.+?)\\(size=(.+?)\\)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"runtime/Java/src/org/antlr/v4/runtime/TokenStreamRewriter.java","lineNumber":287,"sourceCode":"\tpublic void replace(int index, Object text) {\n\t\treplace(DEFAULT_PROGRAM_NAME, index, index, text);\n\t}\n\n\tpublic void replace(int from, int to, Object text) {\n\t\treplace(DEFAULT_PROGRAM_NAME, from, to, text);\n\t}\n\n\tpublic void replace(Token indexT, Object text) {\n\t\treplace(DEFAULT_PROGRAM_NAME, indexT, indexT, text);\n\t}\n\n\tpublic void replace(Token from, Token to, Object text) {\n\t\treplace(DEFAULT_PROGRAM_NAME, from, to, text);\n\t}\n\n\tpublic void replace(String programName, int from, int to, Object text) {\n\t\tif ( from > to || from<0 || to<0 || to >= tokens.size() ) {\n\t\t\tthrow new IllegalArgumentException(\"replace: range invalid: \"+from+\"..\"+to+\"(size=\"+tokens.size()+\")\");\n\t\t}\n\t\tRewriteOperation op = new ReplaceOp(from, to, text);\n\t\tList<RewriteOperation> rewrites = getProgram(programName);\n\t\top.instructionIndex = rewrites.size();\n\t\trewrites.add(op);\n\t}\n\n\tpublic void replace(String programName, Token from, Token to, Object text) {\n\t\treplace(programName,\n\t\t\t\tfrom.getTokenIndex(),\n\t\t\t\tto.getTokenIndex(),\n\t\t\t\ttext);\n\t}\n\n\tpublic void delete(int index) {\n\t\tdelete(DEFAULT_PROGRAM_NAME, index, index);\n\t}\n","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/antlr/antlr4/blob/7d5770395bb7b02eb56e7c62662cb1d7c08f42a3/runtime/Java/src/org/antlr/v4/runtime/TokenStreamRewriter.java#L269-L305","documentation":"TokenStreamRewriter.replace(programName, from, to, text) validates the token index range before queueing a ReplaceOp. It rejects from > to, from < 0, to < 0, and to >= tokens.size(), because the rewriter can only replace tokens that actually exist in the stream. The message reports the offending range and the stream size.","triggerScenarios":"replace(from, to, ...) with from greater than to (inverted arguments); to >= tokens.size() (e.g., tokens.size() instead of tokens.size()-1); negative indexes from sentinel tokens (EOF token index can be -1) passed via from.getTokenIndex(); replace(Token indexT, text) where the token belongs to a different stream.","commonSituations":"Off-by-one when computing the last token index; using ctx.stop.getTokenIndex()+1 assuming another token exists; mixing tokens from a different TokenStream; EOF token (index -1) passed as the from argument.","solutions":["Clamp and order the range before calling: from = Math.max(0, Math.min(from, to)); to = Math.min(to, tokens.size() - 1)","Derive indexes from tokens of the same stream via token.getTokenIndex() instead of computing them manually","Check for EOF/sentinel tokens (getTokenIndex() < 0) before rewriting them"],"exampleFix":"// before\nrewriter.replace(ctx.start.getTokenIndex(), tokens.size(), \"x\"); // to >= size -> throws\n\n// after\nint from = Math.max(0, ctx.start.getTokenIndex());\nint to = Math.min(ctx.stop.getTokenIndex(), tokens.size() - 1);\nrewriter.replace(from, to, \"x\");","handlingStrategy":"validation","validationCode":"int size = tokens.size();\nif (from < 0 || to < from || to >= size) {\n    throw new IllegalArgumentException(\"bad replace range \" + from + \"..\" + to + \" size=\" + size);\n}\nrewriter.replace(from, to, text);","typeGuard":null,"tryCatchPattern":"try { rewriter.replace(from, to, text); }\ncatch (IllegalArgumentException e) { /* log range, skip or clamp and retry once with corrected bounds */ }","preventionTips":["Always derive from/to from token.getTokenIndex() of the same stream","Remember the last valid index is tokens.size() - 1","Reject sentinel/EOF tokens (negative index) before rewriting"],"tags":["antlr","token-stream-rewriter","index-out-of-range","validation"],"backgroundTag":null,"analyzedSha":"7d5770395bb7b02eb56e7c62662cb1d7c08f42a3","analyzedAt":"2026-08-14T14:47:56.354Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}