NationalSecurityAgency/ghidra · error · IllegalArgumentException
Emulator edits require a thread.
Error message
Emulator edits require a thread.
What it means
Thrown as IllegalArgumentException by RW_EMULATOR.setVariable (ControlMode.java:317-322) when coordinates.getThread() is null. Emulator edits are implemented as TraceSchedule patches (patched(thread, ...)), and every schedule step requires a thread; without one the patch cannot be generated. The code comment notes this is a TraceSchedule limitation.
Source
Thrown at Ghidra/Debug/Debugger-api/src/main/java/ghidra/debug/api/control/ControlMode.java:321
}
AddressRange ctxRange = TraceRegisterUtils.rangeForRegister(ctxReg);
if (ctxRange.contains(address)) {
return false;
}
return true;
}
@Override
public CompletableFuture<Void> setVariable(PluginTool tool,
DebuggerCoordinates coordinates, Address address, byte[] data) {
if (!(coordinates.getView() instanceof TraceVariableSnapProgramView)) {
throw new IllegalArgumentException("Cannot emulate using a Fixed Program View");
}
TraceThread thread = coordinates.getThread();
if (thread == null) {
// TODO: Well, technically, only for register edits
// It's a limitation in TraceSchedule. Every step requires a thread
throw new IllegalArgumentException("Emulator edits require a thread.");
}
Language language = coordinates.getPlatform().getLanguage();
TraceSchedule time = coordinates.getTime()
.patched(thread, language,
PatchStep.generateSleigh(language, address, data));
DebuggerCoordinates withTime = coordinates.time(time);
DebuggerTraceManagerService traceManager =
Objects.requireNonNull(tool.getService(DebuggerTraceManagerService.class),
"No trace manager service");
return traceManager.activateAndNotify(withTime, ActivationCause.EMU_STATE_EDIT);
}
@Override
public boolean useEmulatedBreakpoints() {
return true;
}View on GitHub (pinned to d5f144c24d)
Solutions
- Activate/select a thread in the coordinates before any emulator edit: coordinates.thread(someThread).
- Check isVariableEditable(coordinates, ...) returns true (it returns false when thread == null) before calling setVariable.
- If no thread context exists, use RW_TRACE mode for memory-only edits.
Example fix
// before
RW_EMULATOR.setVariable(tool, coordinates, address, data); // no thread
// after
DebuggerCoordinates withThread = coordinates.thread(selectedThread);
if (RW_EMULATOR.isVariableEditable(withThread, address, data.length)) {
RW_EMULATOR.setVariable(tool, withThread, address, data);
} Defensive patterns
Strategy: validation
Validate before calling
if (coordinates.getThread() == null) {
throw new IllegalStateException("emulator edits require an active thread");
}
if (!RW_EMULATOR.isVariableEditable(coordinates, address, data.length)) {
throw new IllegalStateException("not editable in emulator mode");
} Type guard
boolean emuHasThread(DebuggerCoordinates c) {
return c.getThread() != null;
} Try / catch
try {
RW_EMULATOR.setVariable(tool, coordinates, address, data);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("require a thread")) {
coordinates = coordinates.thread(selectThread());
RW_EMULATOR.setVariable(tool, coordinates, address, data);
} else throw e;
} Prevention
- Always select a thread before emulator edits (required for memory AND registers).
- Gate edits on RW_EMULATOR.isVariableEditable() which returns false without a thread.
- Use RW_TRACE for thread-less memory edits.
When it happens
Trigger: Editing any variable in RW_EMULATOR mode while no thread is active. Unlike RW_TRACE (which only needs a thread for register edits), the emulator requires a thread for ALL edits because PatchStep.generateSleigh is thread-bound.
Common situations: A memory edit attempted in emulator mode before a thread is selected; coordinates built without a thread; switching to emulator mode at the process level.
Related errors
- Register edits require a thread.
- Cannot emulate using a Fixed Program View
- Guest address {guestAddress} is not mapped
- Unsupported value: {}
- Invalid value for {}
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/dd06b562c15aa14a.
Report an issue: GitHub.