Tencent/matrix · error · IllegalStateException
backgroundLruKill should only be called in supervisor
Error message
backgroundLruKill should only be called in supervisor
What it means
SupervisorService.backgroundLruKill() performs LRU-based killing of background processes and is restricted to the supervisor process. It throws IllegalStateException when called while ProcessSupervisor.isSupervisor is false, preventing non-supervisor processes from triggering process kills.
Solutions
- Guard the call with `if (ProcessSupervisor.isSupervisor)` before invoking backgroundLruKill.
- Move LRU-kill invocations into supervisor-only code (e.g. inside the SupervisorService).
- Verify ProcessSupervisor.init ran and enable flags make this process the supervisor.
- Skip the operation gracefully (log and return) in non-supervisor processes instead of calling.
Example fix
// before
SupervisorService.backgroundLruKill(killedCallback)
// after
if (ProcessSupervisor.isSupervisor) {
SupervisorService.backgroundLruKill(killedCallback)
} Defensive patterns
Strategy: validation
Validate before calling
if (ProcessSupervisor.isSupervisor) {
SupervisorService.backgroundLruKill(killedCallback)
} else {
MatrixLog.w(TAG, "backgroundLruKill skipped: not supervisor")
} Type guard
fun canBackgroundLruKill(): Boolean =
runCatching { ProcessSupervisor.isSupervisor }.getOrDefault(false) Try / catch
try {
SupervisorService.backgroundLruKill(killedCallback)
} catch (e: IllegalStateException) {
MatrixLog.w(TAG, "lru kill forbidden outside supervisor", e)
} Prevention
- Only invoke LRU kill from the supervisor process.
- Route memory-pressure decisions to a single supervisor-side component.
- Confirm the supervisor role at startup and log mismatches early.
When it happens
Trigger: Calling backgroundLruKill(...) from a subordinate process, or before ProcessSupervisor.init has determined the role (which also surfaces init errors); any call path where the supervisor role check fails.
Common situations: Memory-pressure callbacks that run in every process but invoke backgroundLruKill unconditionally; testing on a device where the supervisor service was not the calling process; disabled supervisor config causing role detection to differ from expectation.
Understand the failure class
Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.
Related errors
- call forbidden
- NOT allow for subordinate processes
- Supervisor NOT initialized yet or Supervisor is disabled!!!
- token with pid=$pid not found
- token with name=$name not found
AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08).
Data as JSON: /api/errors/511ec701c559e6bb.
Report an issue: GitHub.
Appendix: source
Thrown at matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/SupervisorService.kt:285
MatrixLog.d(TAG, "onBind")
return binder
}
override fun onDestroy() {
super.onDestroy()
MatrixLog.e(TAG, "SupervisorService destroyed!!!")
instance = null
}
internal fun backgroundLruKill(
killedCallback: (result: Int, process: String?, pid: Int) -> Unit
) {
if (true != ProcessSupervisor.config?.enable) {
MatrixLog.e(TAG, "supervisor was disabled")
return
}
if (!isSupervisor) {
throw IllegalStateException("backgroundLruKill should only be called in supervisor")
}
if (instance == null) {
throw IllegalStateException("not initialized yet !")
}
targetKilledCallback = killedCallback
val candidate = backgroundProcessLru.firstOrNull {
it.name != MatrixUtil.getProcessName(this)
&& !ProcessSupervisor.config!!.lruKillerWhiteList.contains(it.name)
}
if (candidate != null) {
// DispatchReceiver.dispatchKill(this, candidate.name, candidate.pid)
ProcessSubordinate.manager.dispatchKill(recentScene, candidate.name, candidate.pid)
} else {
killedCallback.invoke(LRU_KILL_NOT_FOUND, null, -1)
}View on GitHub (pinned to 3b8293bd65)