{"record":{"id":"0f8e46b07d86686d","repo":"NationalSecurityAgency/ghidra","slug":"cell-is-not-editable","errorCode":null,"errorMessage":"Cell is not editable","messagePattern":"Cell is not editable","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/EnumeratedColumnTableModel.java","lineNumber":38,"sourceCode":"import java.util.function.Predicate;\n\nimport javax.help.UnsupportedOperationException;\n\nimport ghidra.docking.settings.Settings;\nimport ghidra.framework.plugintool.ServiceProvider;\n\npublic interface EnumeratedColumnTableModel<R> extends RowObjectTableModel<R> {\n\n\tpublic interface EditableDynamicTableColumn<ROW_TYPE, COLUMN_TYPE, DATA_SOURCE>\n\t\t\textends DynamicTableColumn<ROW_TYPE, COLUMN_TYPE, DATA_SOURCE> {\n\t\tdefault public boolean isEditable(ROW_TYPE row, Settings settings, DATA_SOURCE dataSource,\n\t\t\t\tServiceProvider serviceProvider) {\n\t\t\treturn false;\n\t\t}\n\n\t\tdefault public void setValueOf(ROW_TYPE row, COLUMN_TYPE value, Settings settings,\n\t\t\t\tDATA_SOURCE dataSource, ServiceProvider serviceProvider) {\n\t\t\tthrow new UnsupportedOperationException(\"Cell is not editable\");\n\t\t}\n\t}\n\n\tvoid add(R row);\n\n\tvoid addAll(Collection<R> c);\n\n\tvoid notifyUpdated(R row);\n\n\tList<R> notifyUpdatedWith(Predicate<R> predicate);\n\n\tvoid delete(R row);\n\n\tList<R> deleteWith(Predicate<R> predicate);\n\n\tR findFirst(Predicate<R> predicate);\n\n\tpublic void clear();","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/NationalSecurityAgency/ghidra/blob/d5f144c24d6bc53c9cbf4448c6d11143e7696206/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/EnumeratedColumnTableModel.java#L20-L56","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Override setValueOf(ROW_TYPE, COLUMN_TYPE, Settings, DATA_SOURCE, ServiceProvider) in the column to persist the new value.","If the column should stay read-only, ensure isEditable(...) returns false (the default) so the editor is never invoked.","Audit every column where isEditable returns true and confirm each has a matching setValueOf override."],"exampleFix":"// before\nclass MyCol implements EditableDynamicTableColumn<Row, String, Src> {\n  public boolean isEditable(Row r, Settings s, Src d, ServiceProvider sp) {\n    return true; // editing enabled, but no setValueOf -> throws\n  }\n}\n\n// after\nclass MyCol implements EditableDynamicTableColumn<Row, String, Src> {\n  public boolean isEditable(Row r, Settings s, Src d, ServiceProvider sp) {\n    return true;\n  }\n  public void setValueOf(Row r, String val, Settings s, Src d, ServiceProvider sp) {\n    r.setName(val);\n  }\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"boolean canEdit = column.isEditable(row, settings, dataSource, serviceProvider);\nif (canEdit) {\n  // safe to call setValueOf only if the subclass overrides it\n  assert isOverridden(column.getClass(), \"setValueOf\");\n}","tryCatchPattern":"try {\n  column.setValueOf(row, value, settings, dataSource, serviceProvider);\n} catch (UnsupportedOperationException e) {\n  if (\"Cell is not editable\".equals(e.getMessage())) {\n    // column reports editable but has no setter; treat as read-only\n  } else throw e;\n}","preventionTips":["Always pair an isEditable()==true override with a setValueOf override.","Never call setValueOf without first checking isEditable.","In tests, exercise the edit path for every editable column."],"tags":["ghidra","table-column","editing","contract-violation"],"backgroundTag":null,"analyzedSha":"d5f144c24d6bc53c9cbf4448c6d11143e7696206","analyzedAt":"2026-08-14T01:00:57.564Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}