NationalSecurityAgency/ghidra · error · IllegalStateException

Trace must be opened before activated: {}

Error message

Trace must be opened before activated: {}

What it means

DebuggerTraceManagerServicePlugin.activateAndNotify() requires that any non-null target trace already be registered with the manager (present in listenersByTrace, which is populated by openTrace). Activating a trace that was never opened is a state error: IllegalStateException("Trace must be opened before activated: " + newTrace). Note FOLLOW_PRESENT causes a logged ignore instead of a throw, but all other causes throw.

Source

Thrown at Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/tracemgr/DebuggerTraceManagerServicePlugin.java:1164

					.sorted(Comparator.comparing(l -> -l.time))
					.findFirst()
					.map(l -> l.coords)
					.orElse(DebuggerCoordinates.NOWHERE);
		}
	}

	@Override
	public CompletableFuture<Void> activateAndNotify(DebuggerCoordinates coordinates,
			ActivationCause cause) {
		Trace newTrace = coordinates.getTrace();
		synchronized (listenersByTrace) {
			if (newTrace != null && !listenersByTrace.containsKey(newTrace)) {
				if (cause == ActivationCause.FOLLOW_PRESENT) {
					Msg.error(this,
						"Ignoring activation because FOLLOW_PRESENT for non-opened trace");
					return AsyncUtils.nil();
				}
				throw new IllegalStateException(
					"Trace must be opened before activated: " + newTrace);
			}
			if (newTrace == null && ensureActiveTrace) {
				coordinates = getMostRecentCoordinates(); // Might still be NOWHERE
			}
		}

		if (cause == ActivationCause.FOLLOW_PRESENT || cause == ActivationCause.TARGET_UPDATED) {
			if (!isFollowsPresent(newTrace) && cause == ActivationCause.FOLLOW_PRESENT) {
				return AsyncUtils.nil();
			}
			if (current.getTrace() != newTrace) {
				// The snap needs to match upon re-activating this trace.
				try {
					TraceVariableSnapProgramView view = newTrace.getProgramView();
					view.setSnap(coordinates.getViewSnap());
					view.setPlatform(coordinates.getPlatform());
				}

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Open the trace with traceManager.openTrace(trace) (which registers it in listenersByTrace) before activating.
  2. Guard activation by checking the trace is currently open; if not, open it or skip.
  3. For follow-present flows, ensure the cause is FOLLOW_PRESENT so a non-opened trace is ignored rather than throwing.

Example fix

// before
traceManager.activateAndNotify(DebuggerCoordinates.NOWHERE.trace(trace), ActivationCause.SOURCE);
// throws: Trace must be opened before activated

// after
if (!traceManager.getOpenTraces().contains(trace)) {
    traceManager.openTrace(trace);
}
traceManager.activateAndNotify(coordinates, ActivationCause.SOURCE);
Defensive patterns

Strategy: validation

Validate before calling

if (newTrace != null && !traceManager.getOpenTraces().contains(newTrace)) {
    traceManager.openTrace(newTrace);
}
traceManager.activateAndNotify(coordinates, cause);

Type guard

public static boolean isOpenInTool(DebuggerTraceManagerService tm, Trace trace) {
    return trace == null || tm.getOpenTraces().contains(trace);
}

Try / catch

try {
    traceManager.activateAndNotify(coordinates, cause);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("must be opened before activated")) {
        traceManager.openTrace(coordinates.getTrace());
        traceManager.activateAndNotify(coordinates, cause);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling activateAndNotify (or activate) with coordinates pointing at a Trace that was not opened via openTrace. Activating after the trace was closed. Programmatically building DebuggerCoordinates with a foreign/closed trace.

Common situations: Scripts that construct coordinates for a trace loaded but not opened. Re-activating a stale trace reference after the user closed it. Race between close and an activation callback for a non-FOLLOW_PRESENT cause.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/9de847c22c7fb5df. Report an issue: GitHub.