NationalSecurityAgency/ghidra · critical · RuntimeException
Could not instantiate saveable of type
Error message
Could not instantiate saveable of type
What it means
Thrown by AbstractDBTracePropertyMap.doLoad() during deserialization of a Saveable property value from the trace database. It catches InstantiationException, InvocationTargetException, or SecurityException from the reflective call obj.valueClass.getConstructor().newInstance(), meaning the Saveable's value class could not be instantiated. This is a RuntimeException wrapping the original cause, indicating either a broken Saveable implementation, a constructor that throws, or a security manager restriction.
Source
Thrown at Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/map/AbstractDBTracePropertyMap.java:445
byte[] enc = record.getBinaryData(column);
if (enc == null) {
setValue(obj, null);
}
try {
Saveable value = getValue(obj);
if (value == null) {
value = obj.valueClass.getConstructor().newInstance();
setValue(obj, value);
}
ObjectStorage objStorage = new ObjectStorageStreamAdapter(
new ObjectInputStream(new ByteArrayInputStream(enc)));
value.restore(objStorage);
}
catch (IOException e) {
throw new AssertionError(e);
}
catch (InstantiationException | InvocationTargetException | SecurityException e) {
throw new RuntimeException(
"Could not instantiate saveable of type " + obj.valueClass);
}
catch (NoSuchMethodException e) {
throw new RuntimeException("Saveable must have a default constructor");
}
}
}
public static class DBTraceStringPropertyMap
extends AbstractDBTracePropertyMap<String, DBTraceStringPropertyMapEntry> {
public DBTraceStringPropertyMap(String name, DBHandle dbh, OpenMode openMode,
ReadWriteLock lock, TaskMonitor monitor, Language baseLanguage, DBTrace trace,
DBTraceThreadManager threadManager) throws IOException, VersionException {
super(name, dbh, openMode, lock, monitor, baseLanguage, trace, threadManager,
DBTraceStringPropertyMapEntry.class, DBTraceStringPropertyMapEntry::new);
}
View on GitHub (pinned to d5f144c24d)
Solutions
- Inspect the wrapped cause in the RuntimeException to identify the specific failure (InstantiationException = abstract class, InvocationTargetException = constructor threw, SecurityException = manager blocked access).
- Fix the Saveable value class's default constructor so it completes without throwing.
- If the Saveable class changed between versions, ensure a migration/upgrade path exists for old trace databases.
- If the database is corrupt, restore from a backup or re-create the trace.
Example fix
// before
public class MySaveable implements Saveable {
public MySaveable() {
// throws if someField not set
init(someField);
}
}
// after
public class MySaveable implements Saveable {
private Object someField = DEFAULT;
public MySaveable() {
// safe default, no exception
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before opening a trace with Saveable properties, verify value classes
// have accessible default constructors
Class<?> valueClass = /* the registered Saveable class */;
try {
valueClass.getConstructor(); // check no-arg constructor exists
valueClass.getConstructor().newInstance(); // check it doesn't throw
} catch (Exception e) {
// fix the class before opening the trace
} Try / catch
try {
trace.open(programName, monitor);
} catch (RuntimeException e) {
if (e.getCause() instanceof InstantiationException ||
e.getCause() instanceof InvocationTargetException ||
e.getCause() instanceof SecurityException) {
// Saveable value class failed to instantiate
// inspect e.getCause() for details
}
} Prevention
- Ensure every Saveable class stored in property maps has a public no-arg constructor that does not throw.
- Test Saveable instantiation in unit tests.
- Handle Saveable class migrations when upgrading Ghidra versions.
When it happens
Trigger: Loading a trace database that contains property map entries whose Saveable value class fails reflective instantiation. This occurs when the valueClass's default constructor throws an exception, the class is abstract, or a SecurityManager blocks reflective access. The error is triggered during trace open/upgrade when doLoad reads binary data from the DB record.
Common situations: After upgrading Ghidra versions where a Saveable class's constructor signature or initialization logic changed and now throws. When a custom Saveable implementation has a buggy default constructor. When running under a restrictive SecurityManager that blocks reflection.
Related errors
- Saveable must have a default constructor
- Can only directly delete values for maps where the entry is
- Can only directly delete values for maps where the entry is
- The given entry is not in this space
- Platform and prototype disagree in language
AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14).
Data as JSON: /api/errors/3858682bb38bc83b.
Report an issue: GitHub.