{"record":{"id":"dafe021b2026f021","repo":"infinilabs/analysis-ik","slug":"length-0","errorCode":null,"errorMessage":"length < 0","messagePattern":"length < 0","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/wltea/analyzer/core/Lexeme.java","lineNumber":69,"sourceCode":"\tpublic static final int TYPE_CQUAN = 48;\r\n\t\r\n\t//词元的起始位移\r\n\tprivate int offset;\r\n    //词元的相对起始位置\r\n    private int begin;\r\n    //词元的长度\r\n    private int length;\r\n    //词元文本\r\n    private String lexemeText;\r\n    //词元类型\r\n    private int lexemeType;\r\n    \r\n    \r\n\tpublic Lexeme(int offset , int begin , int length , int lexemeType){\r\n\t\tthis.offset = offset;\r\n\t\tthis.begin = begin;\r\n\t\tif(length < 0){\r\n\t\t\tthrow new IllegalArgumentException(\"length < 0\");\r\n\t\t}\r\n\t\tthis.length = length;\r\n\t\tthis.lexemeType = lexemeType;\r\n\t}\r\n\t\r\n    /*\r\n     * 判断词元相等算法\r\n     * 起始位置偏移、起始位置、终止位置相同\r\n     * @see java.lang.Object#equals(Object o)\r\n     */\r\n\tpublic boolean equals(Object o){\r\n\t\tif(o == null){\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\t\r\n\t\tif(this == o){\r\n\t\t\treturn true;\r\n\t\t}\r","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/infinilabs/analysis-ik/blob/6d2d70fd1a237cbf75cde254e8e4d6319b81266c/core/src/main/java/org/wltea/analyzer/core/Lexeme.java#L51-L87","documentation":"The Lexeme constructor (a 'lexeme' is one token produced by the IK segmenter: begin offset + length + type) rejects any token whose character length is negative. A negative length is structurally impossible for a valid token, so this IllegalArgumentException signals that the caller computed begin/end offsets inconsistently. It is an argument-contract guard inside the public constructor org.wltea.analyzer.core.Lexeme#Lexeme(int,int,int,int).","triggerScenarios":"Calling new Lexeme(offset, begin, length, lexemeType) with a negative length argument. Inside the library this happens when a segmenter or LexemePath merge computes length as (end - begin) while end < begin — e.g. overlapping lexemes merged in the wrong order, or a custom segmenter appending Lexeme objects with hand-computed offsets. User code that builds Lexeme instances directly (custom similarity/LexemePath experiments) and passes begin > end arithmetic hits it immediately.","commonSituations":"Writing a custom Segmenter plugin that emits Lexemes with begin beyond the current cursor; porting code from an IK version where length was unchecked; unit tests that construct Lexemes with placeholder offsets like (0, 5, -1, 0); downstream code that derives length from two independently computed positions that drift apart when the char buffer is refilled.","solutions":["If you construct Lexeme yourself, compute length as Math.max(0, end - begin) or assert end >= begin before calling the constructor","Audit the two inputs that produce length: in library-internal paths the exception means the AnalyzeContext cursor/offset bookkeeping got corrupted — capture the input text and the segmenter that was active (useSmart on/off) and reduce to a minimal repro","If reproducible against the stock segmenters with normal Chinese text, file an upstream issue with the failing input string — stock paths should never produce negative lengths","Never wrap the call in a silent catch that substitutes length=0; that masks offset corruption and produces wrong term positions downstream"],"exampleFix":"// before\nint end = computeEnd();\nLexeme l = new Lexeme(offset, begin, end - begin, Lexeme.TYPE_CJK_NORMAL); // throws when end < begin\n\n// after\nint end = computeEnd();\nif (end < begin) throw new IllegalStateException(\"corrupted offsets: begin=\" + begin + \", end=\" + end);\nLexeme l = new Lexeme(offset, begin, end - begin, Lexeme.TYPE_CJK_NORMAL);","handlingStrategy":"validation","validationCode":"if (end - begin < 0) {\n    throw new IllegalStateException(\"invalid lexeme bounds: begin=\" + begin + \", end=\" + end);\n}\nLexeme lexeme = new Lexeme(offset, begin, end - begin, Lexeme.TYPE_CJK_NORMAL);","typeGuard":"private static boolean isValidLexemeLength(int begin, int end) {\n    return end >= begin; // length = end - begin must be >= 0\n}","tryCatchPattern":"try {\n    Lexeme lexeme = new Lexeme(offset, begin, length, type);\n} catch (IllegalArgumentException e) {\n    if (!\"length < 0\".equals(e.getMessage())) throw e;\n    throw new IllegalStateException(\"segmenter produced inverted bounds at offset \" + offset, e);\n}","preventionTips":["Treat negative length as a symptom of corrupted offset bookkeeping, never as a data value to sanitize","When writing custom segmenters, always derive length from end - begin and assert end >= begin","Log the input buffer window around the cursor when the exception fires — it identifies the offending segmenter"],"tags":["java","ik-analyzer","argument-validation","tokenization"],"backgroundTag":null,"analyzedSha":"6d2d70fd1a237cbf75cde254e8e4d6319b81266c","analyzedAt":"2026-08-14T14:39:54.684Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}