{"record":{"id":"392e0fac810780ef","repo":"Tencent/QMUI_Android","slug":"unsafeaddeffect-start-start-is-bigger-than-end","errorCode":null,"errorMessage":"unsafeAddEffect: start($start) is bigger than end($end)","messagePattern":"unsafeAddEffect: start\\(\\$start\\) is bigger than end\\(\\$end\\)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"type/src/main/java/com/qmuiteam/qmui/type/TypeModel.kt","lineNumber":65,"sourceCode":"\n    fun addTextColorEffect(start: Int, end: Int, textColor: Int): EffectRemover? {\n        val types: MutableList<Int> = ArrayList()\n        types.add(TypeEnvironment.TYPE_TEXT_COLOR)\n        return unsafeAddEffect(start, end, types) { env -> env.textColor = textColor }\n    }\n\n    fun addUnderLineEffect(start: Int, end: Int, underLineColor: Int, underLineHeight: Int): EffectRemover? {\n        val types: MutableList<Int> = ArrayList()\n        types.add(TypeEnvironment.TYPE_BORDER_BOTTOM_WIDTH)\n        types.add(TypeEnvironment.TYPE_BORDER_BOTTOM_COLOR)\n        return unsafeAddEffect(\n            start, end, types\n        ) { env -> env.setBorderBottom(underLineHeight, underLineColor) }\n    }\n\n    fun unsafeAddEffect(start: Int, end: Int, types: List<Int>, environmentUpdater: EnvironmentUpdater): EffectRemover? {\n        if (start > end) {\n            throw RuntimeException(\"unsafeAddEffect: start($start) is bigger than end($end)\")\n        }\n        val elementStart = getByPos(start)\n        val elementEnd = getByPos(end)\n        if (elementStart == null || elementEnd == null) {\n            return null\n        }\n        for (type in types) {\n            elementStart.addSaveType(type)\n            elementEnd.addRestoreType(type)\n        }\n        elementStart.addEnvironmentUpdater(environmentUpdater)\n        firstEffect = if (firstEffect == null) {\n            elementStart\n        } else {\n            elementStart.insertEffectTo(firstEffect!!)\n        }\n        firstEffect = elementEnd.insertEffectTo(firstEffect!!)\n        return DefaultEffectRemove(this, start, end, types, environmentUpdater)","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/Tencent/QMUI_Android/blob/026e7d486677d6593a96689cd590ec3561176717/type/src/main/java/com/qmuiteam/qmui/type/TypeModel.kt#L47-L83","documentation":"TypeModel.unsafeAddEffect attaches a text effect (typeface, text size, background, color, underline) to a [start, end) character range. It requires start <= end; a start greater than end cannot form a valid element range and throws a RuntimeException immediately, before any element lookup.","triggerScenarios":"Calling unsafeAddEffect(start, end, types, updater) — or any wrapper like addTypefaceEffect/addTextSizeEffect/addBgEffect/addTextColorEffect/addUnderLineEffect routed to it — with start > end (e.g. swapped arguments or a range computed against a different string).","commonSituations":"Computing highlight ranges by searching text after edits, so stale offsets produce inverted ranges; swapping the two positional arguments; applying effects before the text model is updated to match the offsets.","solutions":["Validate start <= end before calling; swap or clamp the range if inverted.","Recompute the offsets against the current text content (the offsets refer to positions in the TypeModel, not the original string).","Check the return value as well: if getByPos returns null for either endpoint the call silently no-ops (returns null), so log/verify the effect was applied."],"exampleFix":"// before\ntypeModel.unsafeAddEffect(end, start, types, updater); // throws when end > start\n\n// after\nint s = Math.min(start, end);\nint e = Math.max(start, end);\nif (s <= e) {\n    typeModel.unsafeAddEffect(s, e, types, updater);\n}","handlingStrategy":"validation","validationCode":"public static void addEffectSafe(TypeModel m, int start, int end, List<Integer> types, EnvironmentUpdater u) {\n    if (start > end) throw new IllegalArgumentException(\"start(\" + start + \") > end(\" + end + \")\");\n    m.unsafeAddEffect(start, end, types, u);\n}","typeGuard":null,"tryCatchPattern":"try {\n    typeModel.unsafeAddEffect(start, end, types, updater);\n} catch (RuntimeException e) {\n    Log.w(\"TypeModel\", \"invalid effect range: \" + start + \"..\" + end, e);\n}","preventionTips":["Normalize ranges with Math.min/Math.max before applying effects.","Recompute offsets after any text edit; stale offsets often invert ranges.","Keep a single helper for effect application that enforces start <= end."],"tags":["android","range-validation","argument-order","type-system"],"backgroundTag":"argument-out-of-range","analyzedSha":"026e7d486677d6593a96689cd590ec3561176717","analyzedAt":"2026-09-06T13:32:24.816Z","contentChangedAt":"2026-09-06T13:32:24.816Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}