NationalSecurityAgency/ghidra · error · IllegalStateException
Ghidra python interpreter has already been cleaned up.
Error message
Ghidra python interpreter has already been cleaned up.
What it means
Thrown by GhidraJythonInterpreter.push() (interactive line execution) when the interpreter's cleanedUp flag is true. Once cleanup() runs, the underlying Jython/InteractiveInterpreter state is torn down and the instance is permanently unusable. The class deliberately removes any reset path, so the only valid action is to obtain a fresh interpreter via GhidraJythonInterpreter.get().
Source
Thrown at Ghidra/Extensions/Jython/src/main/java/ghidra/jython/GhidraJythonInterpreter.java:166
systemState.path.append(Py.newStringOrUnicode(pyDevSrcDir.getAbsolutePath()));
}
}
}
/**
* Pushes (executes) a line of Python to the interpreter.
*
* @param line the line of Python to push to the interpreter
* @param script a PythonScript from which we load state (or null)
* @return true if more input is needed before execution can occur
* @throws PyException if an unhandled exception occurred while executing the line of python
* @throws IllegalStateException if this interpreter has been cleaned up.
*/
public synchronized boolean push(String line, JythonScript script)
throws PyException, IllegalStateException {
if (cleanedUp) {
throw new IllegalStateException(
"Ghidra python interpreter has already been cleaned up.");
}
initializePythonPath();
injectScriptHierarchy(script);
if (buffer.length() > 0) {
buffer.append("\n");
}
buffer.append(line);
Py.getThreadState().tracefunc = interruptTraceFunction;
Py.getSystemState().stderr = getSystemState().stderr; // needed to properly display SyntaxError
boolean more;
try {
more = runsource(buffer.toString(), "python");
getSystemState().stderr.invoke("flush");
if (!more) {
resetbuffer();View on GitHub (pinned to d5f144c24d)
Solutions
- Stop using the cleaned-up instance; call GhidraJythonInterpreter.get() to create a new interpreter and route subsequent push() calls to it.
- Track the interpreter lifecycle with the owning component (e.g. dispose()/cleanup()) and null out references so stale callers cannot reach a dead instance.
- If unsure whether the instance is live, guard with a state check or catch IllegalStateException and reinitialize before retrying once.
Example fix
// before interpreter.cleanup(); // ... later, in another thread interpreter.push(line, script); // throws IllegalStateException // after interpreter.cleanup(); interpreter = GhidraJythonInterpreter.get(); interpreter.push(line, script);
Defensive patterns
Strategy: validation
Validate before calling
// There is no public isCleanedUp(); track lifecycle yourself, or wrap.
public boolean isInterpreterUsable(GhidraJythonInterpreter i) {
return i != null; // add your own 'alive' flag tracked alongside cleanup()
} Type guard
null
Try / catch
try {
interpreter.push(line, script);
} catch (IllegalStateException e) {
if (e.getMessage().contains("already been cleaned up")) {
interpreter = GhidraJythonInterpreter.get(); // recreate once
interpreter.push(line, script);
} else throw e;
} Prevention
- Tie interpreter ownership to a component lifecycle; call cleanup() only in dispose() and null the reference.
- Never cache an interpreter across tool open/close cycles.
- Route all push() calls through a single accessor that refreshes the instance after cleanup.
When it happens
Trigger: Calling interpreter.push(line, script) after interpreter.cleanup() has been invoked on the same instance, e.g. a Jython REPL component that was disposed but a queued or background task still submits a line; or a long-lived JythonScript holding a stale interpreter reference whose owning plugin/tool was closed.
Common situations: Closing the Jython interpreter plugin window or the CodeBrowser tool while a script thread is mid-execution; headless runs that reuse an interpreter across script invocations after teardown; UI actions dispatched after the interactive console provider was disposed.
Related errors
- Script does not exist: {scriptName}
- Failed to find the jython home directory at: {jythonHomeDir}
- Failed to create the jython cache directory at: {cacheDir}
- Failed to create the jython-src directory at: {jythonSrcDest
- Failed to find the module's jython-src directory
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/a35d50e3da4d42c0.
Report an issue: GitHub.