Tencent/matrix · error · RuntimeException

Should not call this from main thread!

Error message

Should not call this from main thread!

What it means

WarmUpService.checkThread() throws a RuntimeException if the current thread is the Android main (UI) thread. Backtrace warm-up work (binding, library loading) must never run on the main thread because it performs blocking I/O that would jank or ANR the UI. The guard exists to fail fast when callers misuse the service from the wrong thread.

Solutions

  1. Move the connect()/warm-up call onto a background thread, e.g. new Thread(() -> warmUpService.connect(...)).start() or a coroutine on Dispatchers.IO.
  2. Post the call to a worker Handler: new Handler(HandlerThread looper).post(this::connect).
  3. If called in Application.onCreate, defer warm-up with an executor or WorkManager instead of the main thread.

Example fix

// before
@Override
protected void onCreate(Bundle s) {
    super.onCreate(s);
    warmUpService.connect(); // throws on main thread
}

// after
@Override
protected void onCreate(Bundle s) {
    super.onCreate(s);
    Executors.newSingleThreadExecutor().execute(warmUpService::connect);
}
Defensive patterns

Strategy: validation

Validate before calling

if (Looper.getMainLooper() == Looper.myLooper()) {
    // move to worker thread before calling connect()
    workerHandler.post(() -> warmUpService.connect());
} else {
    warmUpService.connect();
}

Prevention

When it happens

Trigger: Calling any WarmUpService API that invokes checkThread() (e.g. via connect()) while Looper.getMainLooper() == Looper.myLooper(), i.e. calling it from an Activity onCreate/onResume, a main-thread Handler, or the Application.onCreate main path without spawning a worker thread.

Common situations: Developers initializing Matrix backtrace warm-up directly inside Activity.onCreate or Application.onCreate without a background thread; calling connect() from a main-thread callback or runOnUiThread block.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08). Data as JSON: /api/errors/bc578cdbd1d5fdd4. Report an issue: GitHub.

Appendix: source

Thrown at matrix/matrix-android/matrix-backtrace/src/main/java/com/tencent/matrix/backtrace/WarmUpService.java:100

                mReq = null;
                synchronized (mBound) {
                    mBound[0] = false;
                    mBound.notifyAll();
                }
                MatrixLog.i(TAG, "This remote invoker(%s) disconnected.", this);

                synchronized (mResult) {
                    mResult[0] = null;
                    mResult.notifyAll();
                }
            }
        };

        private final boolean[] mBound = {false};

        private void checkThread() {
            if (Looper.getMainLooper() == Looper.myLooper()) {
                throw new RuntimeException("Should not call this from main thread!");
            }
        }

        @Override
        public boolean isConnected() {
            return mBound[0];
        }

        @Override
        public boolean connect(Context context, Bundle args) {

            checkThread();

            if (mBound[0]) {
                return true;
            }

            MatrixLog.i(TAG, "Start connecting to remote. (%s)", this.hashCode());

View on GitHub (pinned to 3b8293bd65)