NationalSecurityAgency/ghidra · error · TypeMismatchException

Property {} has type {}, not {}

Error message

Property {} has type {}, not {}

What it means

Thrown as TypeMismatchException by getPropertyMap(name, valueClass) when a map exists under name but its stored value class is not exactly equal to the requested valueClass. Equality is by reference identity (==) on the Class objects, so even a compatible subtype will fail this strict variant. Use getPropertyMapExtends for subtype-tolerant lookup.

Source

Thrown at Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/property/DBTraceAddressPropertyManager.java:195

			DBTraceAddressPropertyEntry ent = propertyStore.create();
			ent.set(name, valueClass);
			AbstractDBTracePropertyMap<T, ?> map = doCreateMap(name, OpenMode.CREATE, valueClass);
			ent.map = map;
			propertyMapsByName.put(name, map);
			return map;
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public <T> AbstractDBTracePropertyMap<T, ?> getPropertyMap(String name, Class<T> valueClass) {
		try (LockHold hold = LockHold.lock(lock.readLock())) {
			AbstractDBTracePropertyMap<?, ?> map = propertyMapsByName.get(name);
			if (map == null) {
				return null;
			}
			if (valueClass != map.getValueClass()) {
				throw new TypeMismatchException("Property " + name + " has type " +
					map.getValueClass() + ", not " + valueClass);
			}
			return (AbstractDBTracePropertyMap<T, ?>) map;
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public <T> TracePropertyMap<? extends T> getPropertyMapExtends(String name,
			Class<T> valueClass) {
		try (LockHold hold = LockHold.lock(lock.readLock())) {
			AbstractDBTracePropertyMap<?, ?> map = propertyMapsByName.get(name);
			if (map == null) {
				return null;
			}
			if (!valueClass.isAssignableFrom(map.getValueClass())) {
				throw new TypeMismatchException("Property " + name + " has type " +
					map.getValueClass() + ", which does not extend " + valueClass);

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Query with the exact class the map was created with (check via getPropertyMap(name).getValueClass()).
  2. If you only need a supertype view, call getPropertyMapExtends(name, supertype.class).
  3. If you only need a subtype view, call getPropertyMapSuper (the inverse-tolerant getter).

Example fix

// before
TracePropertyMap<String> m = mgr.getPropertyMap("note", Object.class);
// after
TracePropertyMap<? extends Object> m =
    mgr.getPropertyMapExtends("note", Object.class);
Defensive patterns

Strategy: validation

Validate before calling

AbstractDBTracePropertyMap<?,?> existing = mgr.getPropertyMap(name);
if (existing == null) return null;
if (existing.getValueClass() != valueClass) {
    // decide: use extends/super getter or fail
}
return mgr.getPropertyMap(name, valueClass);

Type guard

static boolean sameValueClass(AbstractDBTracePropertyMap<?,?> m, Class<?> c) {
    return m.getValueClass() == c;
}

Try / catch

try { return mgr.getPropertyMap(name, cls); }
catch (TypeMismatchException e) { /* inspect getValueClass */ }

Prevention

When it happens

Trigger: A map was created as String.class but queried with getPropertyMap("note", Object.class), or created as a Saveable subclass and queried with the parent Saveable class.

Common situations: Two modules share a property name but disagree on the declared value type; refactoring changed a value class while a persisted trace stores the old class.

Related errors


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