Tencent/matrix · error · RuntimeException

sBuffer == null

Error message

 sBuffer == null

What it means

AppMethodBeat.onStart() throws this RuntimeException when the method is called while sBuffer (the internal long[] ring buffer that records method trace timestamps) is still null. sBuffer is allocated during AppMethodBeat.init(); starting the tracer without a buffer would leave the whole method-instrumentation pipeline with nowhere to write, so the library fails fast under statusLock.

Solutions

  1. Ensure AppMethodBeat.init(config) is called (via TracePlugin.onCreate) before any call to onStart/stopAppMethodBeat
  2. Start the plugin through Matrix's plugin lifecycle (Matrix.Builder with TracePlugin) instead of calling core APIs directly
  3. Check that no code path calls stopAppMethodBeat during initialization or re-entry
  4. Verify status handling: re-init after a previous release to reallocate sBuffer

Example fix

// before
TracePlugin trace = new TracePlugin(config);
trace.start(); // onStart called before init allocated sBuffer
// after
Matrix.with().getPlugin(TracePlugin.class); // ensure plugin initialized first
 AppMethodBeat.init(config); // allocates sBuffer
 AppMethodBeat.onStart();
Defensive patterns

Strategy: try-catch

Validate before calling

if (AppMethodBeat.isAppStartTimeCalled() || statusCheck()) { /* ensure init called */ AppMethodBeat.init(config); }

Type guard

if (!tracePlugin.isInitialized()) { tracePlugin.init(config); }

Try / catch

try { AppMethodBeat.onStart(); } catch (RuntimeException e) { MatrixLog.e(TAG, "start before init", e); AppMethodBeat.init(config); AppMethodBeat.onStart(); }

Prevention

When it happens

Trigger: Calling stopAppMethodBeat() (which calls onStart) or AppMethodBeat.onStart() directly before init()/onCreate() has allocated sBuffer, or after the buffer was released without re-initializing. The status check (STATUS_EXPIRED_START <= status < STATUS_STARTED) passes because the delayed realReleaseRunnable was cancelled, but the buffer was never allocated.

Common situations: Startup race where TracePlugin is started before AppMethodBeat.init() completes; calling start APIs manually during Application lifecycle before the plugin's onCreate; a prior release/reset leaving status inconsistent with the buffer state.

Related errors


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

Appendix: source

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

                }
            } catch (Exception e) {
                MatrixLog.e(TAG, "" + e.toString());
            }
        }
    };

    public static AppMethodBeat getInstance() {
        return sInstance;
    }

    @Override
    public void onStart() {
        synchronized (statusLock) {
            if (status < STATUS_STARTED && status >= STATUS_EXPIRED_START) {
                sHandler.removeCallbacks(checkStartExpiredRunnable);
                MatrixHandlerThread.getDefaultHandler().removeCallbacks(realReleaseRunnable);
                if (sBuffer == null) {
                    throw new RuntimeException(TAG + " sBuffer == null");
                }
                MatrixLog.i(TAG, "[onStart] preStatus:%s", status, Utils.getStack());
                status = STATUS_STARTED;
            } else {
                MatrixLog.w(TAG, "[onStart] current status:%s", status);
            }
        }
    }

    @Override
    public void onStop() {
        synchronized (statusLock) {
            if (status == STATUS_STARTED) {
                MatrixLog.i(TAG, "[onStop] %s", Utils.getStack());
                status = STATUS_STOPPED;
            } else {
                MatrixLog.w(TAG, "[onStop] current status:%s", status);
            }

View on GitHub (pinned to 3b8293bd65)