NationalSecurityAgency/ghidra · error · IllegalArgumentException

Thread with key %d does not exist in given trace

Error message

Thread with key %d does not exist in given trace

What it means

Step.requireThread throws this when the resolved thread is null but a specific key (not -1) was requested. This means threadManager.getThread(key) returned null — no thread with that key exists in the trace. The key is a long identifier assigned to each thread when it is created in the trace.

Source

Thrown at Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/time/schedule/Step.java:115

	default int getTypeOrder() {
		return getType().ordinal();
	}

	boolean isNop();

	long getThreadKey();

	default boolean isEventThread() {
		return getThreadKey() == -1;
	}

	static TraceThread requireThread(TraceThread thread, long key) {
		if (thread == null) {
			if (key == -1) {
				throw new IllegalArgumentException("Thread must be given, e.g., 0:t1-3, " +
					"since the last thread or snapshot event thread is not given.");
			}
			throw new IllegalArgumentException(
				"Thread with key %d does not exist in given trace".formatted(key));
		}
		return thread;
	}

	default TraceThread getThread(TraceThreadManager tm, TraceThread eventThread) {
		long key = getThreadKey();
		return requireThread(isEventThread() ? eventThread : tm.getThread(key), key);
	}

	long getTickCount();

	long getSkipCount();

	long getPatchCount();

	/**
	 * Check if the given step can be combined with this one

View on GitHub (pinned to d5f144c24d)

Solutions

  1. List available threads and their keys: trace.getThreadManager().getAllThreads() and use a valid key
  2. Re-derive the schedule from the current trace's thread keys
  3. If the thread was deleted, either recreate it or update the schedule to reference an existing thread
  4. Validate the key before stepping: trace.getThreadManager().getThread(key) != null

Example fix

// before
// t5 may not exist in this trace
TraceSchedule.parse("0:t5-10", Source.ABNORMAL, TimeRadix.DEC);
// after
// look up an actual thread key
TraceThread t = trace.getThreadManager().getAllThreads().get(0);
String spec = "0:t" + t.getKey() + "-10";
TraceSchedule.parse(spec, Source.ABNORMAL, TimeRadix.DEC);
Defensive patterns

Strategy: validation

Validate before calling

boolean threadExists(Trace trace, long key) {
    return key == -1 || trace.getThreadManager().getThread(key) != null;
}

Type guard

// N/A

Try / catch

try {
    TraceThread thread = step.getThread(tm, eventThread);
} catch (IllegalArgumentException e) {
    // thread key is stale; list available threads
    List<TraceThread> all = tm.getAllThreads();
    // re-derive schedule with a valid key
}

Prevention

When it happens

Trigger: Calling step.getThread() where the step references a thread key that does not exist in the trace's ThreadManager. Using a schedule from a different trace session where thread keys were assigned differently. Referencing a thread that was deleted or never created.

Common situations: Reusing a schedule string across trace sessions — thread keys are per-trace and may differ. Deleting a thread from the trace after the schedule was created. Loading a trace that was partially corrupted or is missing thread records. Using stale schedule bookmarks from a previous emulation session.

Related errors


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