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
- Move the connect()/warm-up call onto a background thread, e.g. new Thread(() -> warmUpService.connect(...)).start() or a coroutine on Dispatchers.IO.
- Post the call to a worker Handler: new Handler(HandlerThread looper).post(this::connect).
- 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
- Always invoke warm-up/backtrace APIs from a dedicated HandlerThread or executor.
- Never call blocking SDK methods directly inside Activity/Application lifecycle callbacks on the main thread.
- Centralize warm-up calls in a background-init helper used app-wide.
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
- Custom library loader is not supported in isolate process…
- must be init in main thread!
- Matrix init, Matrix should not be null.
- you must init Matrix sdk first
- matrix init, application is null
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)