Tencent/matrix · error · RuntimeException

origin == this

Error message

 origin == this

What it means

LooperMonitor's Printer (LooperObserver) dispatches messages to the previously-registered origin printer and then throws if origin == this, i.e. the monitor itself has been chained into the Looper's printer list twice. That would cause infinite/degenerate dispatch loops, so the library detects the self-referential registration and throws.

Solutions

  1. Ensure LooperMonitor.unRegister/stop is called before registering again (match init/release lifecycle)
  2. Do not call register() twice; guard with an isValid/installed flag
  3. Restart the plugin only after its full release cycle completes
  4. Check for duplicated plugin start from multiple entry points

Example fix

// before
LooperMonitor.register(listener);
LooperMonitor.register(listener); // second wrap: origin == this
// after
LooperMonitor.unRegister();
LooperMonitor.register(listener);
Defensive patterns

Strategy: validation

Validate before calling

if (LooperMonitor.isRegistered()) { LooperMonitor.unRegister(); } // before re-registering

Type guard

assert !LooperMonitor.isValid || !isSelfRegistered();

Try / catch

try { LooperMonitor.register(listener); } catch (RuntimeException e) { Log.w(TAG, "printer already installed", e); LooperMonitor.unRegister(); LooperMonitor.register(listener); }

Prevention

When it happens

Trigger: Calling LooperMonitor.register()/start() twice without an intervening unregister/stop, so setMessageLogging wrapped the monitor with itself as origin; concurrent registration from multiple threads during the check window.

Common situations: Trace plugin restarted (onStart/onStop cycles) without LooperMonitor releasing the old printer; a crash or missed unregister leaving the monitor installed, then a second install; re-init of UIThreadMonitor while the Looper still holds the old printer.

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/10f3dcbb93a31339. Report an issue: GitHub.

Appendix: source

Thrown at matrix/matrix-android/matrix-trace-canary/src/main/java/com/tencent/matrix/trace/core/LooperMonitor.java:326

        }
    }


    class LooperPrinter implements Printer {
        public Printer origin;
        boolean isHasChecked = false;
        boolean isValid = false;

        LooperPrinter(Printer printer) {
            this.origin = printer;
        }

        @Override
        public void println(String x) {
            if (null != origin) {
                origin.println(x);
                if (origin == this) {
                    throw new RuntimeException(TAG + " origin == this");
                }
            }

            if (!isHasChecked) {
                isValid = x.charAt(0) == '>' || x.charAt(0) == '<';
                isHasChecked = true;
                if (!isValid) {
                    MatrixLog.e(TAG, "[println] Printer is inValid! x:%s", x);
                }
            }

            if (isValid) {
                dispatch(x.charAt(0) == '>', x);
            }

        }
    }

View on GitHub (pinned to 3b8293bd65)