NationalSecurityAgency/ghidra · error · IllegalArgumentException

@DBAnnotatedColumn fields must be static. Got {}

Error message

@DBAnnotatedColumn fields must be static. Got {}

What it means

DBCachedObjectStoreFactory.writeColumnNumbers scans every declared field of a DBAnnotatedObject subclass for @DBAnnotatedColumn. That annotation injects a shared DBObjectColumn handle into the class so code can reference a column programmatically. The handle MUST be a static field because it is shared across all rows; an instance field would be re-injected per object and defeat the purpose, so a non-static field is rejected at store-build time with IllegalArgumentException.

Source

Thrown at Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/DBCachedObjectStoreFactory.java:1172

		 * Initialize the static {@link DBObjectColumn} fields marked with {@link DBAnnotatedColumn}
		 * 
		 * @param objectType the clas of objects being described
		 * @param numbersByName the assigned column numbers by user-defined name
		 */
		void writeColumnNumbers(Class<? extends DBAnnotatedObject> objectType,
				Map<String, Integer> numbersByName) {
			Class<?> superType = objectType.getSuperclass();
			if (DBAnnotatedObject.class.isAssignableFrom(superType)) {
				writeColumnNumbers(superType.asSubclass(DBAnnotatedObject.class), numbersByName);
			}
			for (Field f : objectType.getDeclaredFields()) {
				DBAnnotatedColumn annotation = f.getAnnotation(DBAnnotatedColumn.class);
				if (annotation == null) {
					continue;
				}
				int mod = f.getModifiers();
				if (!Modifier.isStatic(mod)) {
					throw new IllegalArgumentException(
						"@" + DBAnnotatedColumn.class.getSimpleName() +
							" fields must be static. Got " + f);
				}
				if (f.getType() != DBObjectColumn.class) {
					throw new IllegalArgumentException(
						"@" + DBAnnotatedColumn.class.getSimpleName() + " fields must be " +
							DBObjectColumn.class.getSimpleName() + " type. Got " + f);
				}

				String name = annotation.value();

				Integer columnNumber = numbersByName.get(name);
				if (columnNumber == null) {
					throw new IllegalArgumentException("Cannot find column '" + name + "' for @" +
						DBAnnotatedColumn.class.getSimpleName() + " on " + f);
				}

				f.setAccessible(true);

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Add the `static` modifier to the annotated field.
  2. Confirm the field is a true class field (static, optionally final) that should hold one DBObjectColumn per type.
  3. If you actually wanted per-row data, switch the annotation to @DBAnnotatedField instead.

Example fix

// before
@DBAnnotatedColumn("name")
DBObjectColumn NAME;
// after
@DBAnnotatedColumn("name")
static DBObjectColumn NAME;
Defensive patterns

Strategy: validation

Validate before calling

// Before opening the store, ensure every @DBAnnotatedColumn field is static.
for (Field f : objectType.getDeclaredFields()) {
    if (f.isAnnotationPresent(DBAnnotatedColumn.class) && !Modifier.isStatic(f.getModifiers())) {
        throw new IllegalStateException("Non-static @DBAnnotatedColumn field: " + f);
    }
}

Prevention

When it happens

Trigger: A field carrying @DBAnnotatedColumn is declared without the `static` modifier (e.g. `@DBAnnotatedColumn("name") DBObjectColumn NAME;`). The guard is literally `if (!Modifier.isStatic(mod)) throw ...`, hit the first time a store/table is opened for that object type.

Common situations: Copying the annotation from a @DBAnnotatedField (instance) field and forgetting `static`; refactoring that drops the modifier; IDE auto-format or codegen that omits it; converting an instance column handle to a class handle.

Related errors


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