Tencent/matrix · error · IllegalStateException
call forbidden
Error message
call forbidden
What it means
DispatcherStateOwner.syncStates() is an internal API meant to be invoked only by the ProcessSupervisor to push owner states to subordinate processes. It throws IllegalStateException("call forbidden") when called from any process that is not the supervisor, to prevent app code from corrupting supervisor-driven state synchronization.
Solutions
- Do not call syncStates from app code; it is supervisor-internal. Use the public owner APIs or let the supervisor drive synchronization.
- Guard the call site with `if (ProcessSupervisor.isSupervisor)` before invoking.
- If subordinate processes need updated state, trigger it via the supervisor (e.g. scene dispatch from the supervisor side).
- Catch IllegalStateException as a safety net when probing process roles at runtime.
Example fix
// before
DispatcherStateOwner.syncStates(token, scene)
// after
if (ProcessSupervisor.isSupervisor) {
DispatcherStateOwner.syncStates(token, scene)
} Defensive patterns
Strategy: validation
Validate before calling
if (!ProcessSupervisor.isSupervisor) {
MatrixLog.w(TAG, "syncStates is supervisor-only, skipping")
return
}
DispatcherStateOwner.syncStates(token, scene) Type guard
fun canSyncStates(): Boolean =
runCatching { ProcessSupervisor.isSupervisor }.getOrDefault(false) Try / catch
try {
DispatcherStateOwner.syncStates(token, scene)
} catch (e: IllegalStateException) {
MatrixLog.w(TAG, "syncStates called outside supervisor", e)
} Prevention
- Treat syncStates as internal API; never call it from app code.
- Guard every supervisor API call with ProcessSupervisor.isSupervisor.
- Document process-role invariants at call sites that mix supervisor/subordinate logic.
When it happens
Trigger: Application code (or a subordinate process) calling DispatcherStateOwner.syncStates(token, scene) directly; accidentally linking or invoking the supervisor-only static method from non-supervisor code paths.
Common situations: Trying to force a state sync after seeing stale owner states; copy-pasting supervisor-side code into a subordinate process; custom dispatch logic that bypasses ProcessSupervisor.
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.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Supervisor NOT initialized yet or Supervisor is disabled!!!
- backgroundLruKill should only be called in supervisor
- NOT allow to observe with DESTROYED lifecycle owner
- NOT initialized yet
- NOT initialized yet
AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08).
Data as JSON: /api/errors/15794a49060b4cf2.
Report an issue: GitHub.
Appendix: source
Thrown at matrix/matrix-android/matrix-android-lib/src/main/java/com/tencent/matrix/lifecycle/supervisor/DispatcherStateOwner.kt:46
fun ownersToProcessTokens(context: Context) =
dispatchOwners.values
.map { ProcessToken.current(context, it.name, it.attachedSource.active()) }
.toTypedArray()
fun dispatchOn(name: String) {
dispatchOwners[name]?.dispatchOn()
}
fun dispatchOff(name: String) {
dispatchOwners[name]?.dispatchOff()
}
/**
* call from supervisor
*/
fun syncStates(supervisorToken: ProcessToken, scene: String) {
if (!ProcessSupervisor.isSupervisor) {
throw IllegalStateException("call forbidden")
}
dispatchOwners.forEach {
val active = it.value.active()
MatrixLog.i(ProcessSupervisor.tag, "syncStates: ${it.key} $active")
ProcessSubordinate.manager.dispatchState(supervisorToken, scene, it.key, active)
}
}
fun attach(application: Application) {
dispatchOwners.forEach {
it.value.apply {
attachedObserver?.let { o -> attachedSource.removeObserver(o) } // prevent double-observe
attachedObserver = object : IStateObserver, ISerialObserver {
override fun on() {
MatrixLog.d(ProcessSupervisor.tag, "attached ${it.key} turned ON")
safeApply("${ProcessSupervisor.tag}.${it.key}") {
ProcessSupervisor.supervisorProxy?.onStateChanged(
ProcessToken.current(application, it.key, true)View on GitHub (pinned to 3b8293bd65)