NationalSecurityAgency/ghidra · error · UnsupportedOperationException

Cell is not editable

Error message

Cell is not editable

What it means

Default implementation of EditableDynamicTableColumn.setValueOf() inside EnumeratedColumnTableModel. It throws because the base contract makes columns read-only by default (isEditable returns false); a subclass that enables editing via isEditable() must also override setValueOf() to actually store the value. Attempting to write through a column whose editing was never implemented hits this guard.

Source

Thrown at Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/EnumeratedColumnTableModel.java:38

import java.util.function.Predicate;

import javax.help.UnsupportedOperationException;

import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.ServiceProvider;

public interface EnumeratedColumnTableModel<R> extends RowObjectTableModel<R> {

	public interface EditableDynamicTableColumn<ROW_TYPE, COLUMN_TYPE, DATA_SOURCE>
			extends DynamicTableColumn<ROW_TYPE, COLUMN_TYPE, DATA_SOURCE> {
		default public boolean isEditable(ROW_TYPE row, Settings settings, DATA_SOURCE dataSource,
				ServiceProvider serviceProvider) {
			return false;
		}

		default public void setValueOf(ROW_TYPE row, COLUMN_TYPE value, Settings settings,
				DATA_SOURCE dataSource, ServiceProvider serviceProvider) {
			throw new UnsupportedOperationException("Cell is not editable");
		}
	}

	void add(R row);

	void addAll(Collection<R> c);

	void notifyUpdated(R row);

	List<R> notifyUpdatedWith(Predicate<R> predicate);

	void delete(R row);

	List<R> deleteWith(Predicate<R> predicate);

	R findFirst(Predicate<R> predicate);

	public void clear();

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Override setValueOf(ROW_TYPE, COLUMN_TYPE, Settings, DATA_SOURCE, ServiceProvider) in the column to persist the new value.
  2. If the column should stay read-only, ensure isEditable(...) returns false (the default) so the editor is never invoked.
  3. Audit every column where isEditable returns true and confirm each has a matching setValueOf override.

Example fix

// before
class MyCol implements EditableDynamicTableColumn<Row, String, Src> {
  public boolean isEditable(Row r, Settings s, Src d, ServiceProvider sp) {
    return true; // editing enabled, but no setValueOf -> throws
  }
}

// after
class MyCol implements EditableDynamicTableColumn<Row, String, Src> {
  public boolean isEditable(Row r, Settings s, Src d, ServiceProvider sp) {
    return true;
  }
  public void setValueOf(Row r, String val, Settings s, Src d, ServiceProvider sp) {
    r.setName(val);
  }
}
Defensive patterns

Strategy: type-guard

Type guard

boolean canEdit = column.isEditable(row, settings, dataSource, serviceProvider);
if (canEdit) {
  // safe to call setValueOf only if the subclass overrides it
  assert isOverridden(column.getClass(), "setValueOf");
}

Try / catch

try {
  column.setValueOf(row, value, settings, dataSource, serviceProvider);
} catch (UnsupportedOperationException e) {
  if ("Cell is not editable".equals(e.getMessage())) {
    // column reports editable but has no setter; treat as read-only
  } else throw e;
}

Prevention

When it happens

Trigger: A subclass overrides isEditable(...) to return true but forgets to override setValueOf(...). The table framework calls setValueOf when the user finishes editing a cell in a column that reports itself editable.

Common situations: Enabling cell editing by flipping isEditable to true during feature development without implementing the setter; copying an editable column pattern but omitting the write logic; a third-party column implementation that only half-implements the editable contract.

Related errors


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