Tencent/QMUI_Android · error · IllegalArgumentException

start must >= 0 and < text.length

Error message

start must >= 0 and < text.length

What it means

The private ElementList compile(CharSequence, int, int, boolean) in QMUIQQFaceCompiler validates the substring bounds before parsing text for QQ face codes. If start is negative or past the end of the text, no valid element can be produced and an IllegalArgumentException is thrown. It is invoked recursively while scanning text and from createTouchSpanElement when measuring touch spans.

Source

Thrown at qmui/src/main/java/com/qmuiteam/qmui/qqface/QMUIQQFaceCompiler.java:97

    }

    public ElementList compile(CharSequence text) {
        if (QMUILangHelper.isNullOrEmpty(text)) {
            return null;
        }
        return compile(text, 0, text.length());
    }

    public ElementList compile(CharSequence text, int start, int end) {
        return compile(text, start, end, false);
    }

    private ElementList compile(CharSequence text, int start, int end, boolean inSpan) {
        if (QMUILangHelper.isNullOrEmpty(text)) {
            return null;
        }
        if (start < 0 || start >= text.length()) {
            throw new IllegalArgumentException("start must >= 0 and < text.length");
        }
        if (end <= start) {
            throw new IllegalArgumentException("end must > start");
        }
        int size = text.length();

        if (end > size) {
            end = size;
        }

        boolean hasClickableSpans = false;
        QMUITouchableSpan[] spans = null;
        int[] spanInfo = null;
        if (!inSpan && (text instanceof Spannable)) {
            final Spannable spannable = (Spannable) text;
            spans = ((Spannable) text).getSpans(
                    0,
                    text.length() - 1,

View on GitHub (pinned to 026e7d4866)

Solutions

  1. Clamp/validate start before calling: ensure 0 <= start && start < text.length().
  2. If using an offset derived from a Spannable, verify it was computed against the current text, and recompile after text changes.
  3. Check the public entry points (compile(text) etc.) — if text can be empty, guard with QMUILangHelper.isNullOrEmpty before calling.
  4. Report/log if internal createTouchSpanElement produces out-of-range offsets; usually means the Spannable was modified after compilation.

Example fix

// before
compiler.compile(text, someOffset); // someOffset may equal text.length()

// after
if (someOffset >= 0 && someOffset < text.length()) {
    compiler.compile(text, someOffset);
}
Defensive patterns

Strategy: validation

Validate before calling

if (text != null && start >= 0 && start < text.length()) {
    compiler.compile(text, start);
}

Type guard

boolean canCompile(CharSequence text, int start) {
    return text != null && !text.toString().isEmpty()
        && start >= 0 && start < text.length();
}

Try / catch

try {
    compiler.compile(text, start);
} catch (IllegalArgumentException e) {
    Log.w(TAG, "invalid compile range: " + start, e);
}

Prevention

When it happens

Trigger: Calling the public compile(text)/compile(text, start) with a negative start or start >= text.length(); internal recursion computing a bad start (e.g. from a Span whose offsets are inconsistent with the text, such as after mutating text without recompiling).

Common situations: Passing an empty CharSequence to an overload without the isNullOrEmpty guard, computing span offsets against stale text, or misusing the public start-offset overload with an offset beyond the string.

Related errors


AI-assisted analysis of Tencent/QMUI_Android@026e7d4866 (2026-09-06). Data as JSON: /api/errors/d9526375886bd45e. Report an issue: GitHub.