opf/openproject · error · ArgumentError
Unsupported model for inplace edit
Error message
Unsupported model for inplace edit
What it means
InplaceEditFieldsController#resolve_model_class takes the 'model' request parameter, camelizes it, and resolves it only against classes present in OpenProject::InplaceEdit::UpdateRegistry. The resolved class must additionally be an ApplicationRecord descendant that responds to .visible; otherwise ArgumentError('Unsupported model for inplace edit'). This whitelist exists because the endpoint would otherwise allow arbitrary attribute edits on any model.
Source
Thrown at app/controllers/inplace_edit_fields_controller.rb:119
end
def find_model
model_class = resolve_model_class(params[:model])
@model = model_class.visible.find(params[:id])
rescue ActiveRecord::RecordNotFound, ArgumentError
head :not_found
end
def resolve_model_class(model_param)
return nil if model_param.blank?
model_class =
update_registry.resolve_model_class(model_param)
unless model_class &&
model_class < ApplicationRecord &&
model_class.respond_to?(:visible)
raise ArgumentError, "Unsupported model for inplace edit"
end
model_class
end
def set_attribute
@attribute = params[:attribute].to_sym
end
def authorize_project_custom_field_visibility!
return unless @model.is_a?(Project)
custom_field_id = @attribute.to_s.delete_prefix("custom_field_").to_i
unless ProjectCustomField.visible(current_user, project: @model).exists?(custom_field_id)
head :not_found
end
end
View on GitHub (pinned to d9742c43f3)
Solutions
- Only request inplace edits for models registered in OpenProject::InplaceEdit::UpdateRegistry (list keys in console).
- If a legitimate model is missing, register it with handler and contract so it passes both resolve_model_class and invoke_update_handler.
- Ensure the registered class is an ActiveRecord model exposing a .visible scope.
Example fix
# before (client requests an unregistered model)
fetch('/inplace_edit_fields?model=meeting&attribute=name')
# after (guard client-side against the whitelist)
const SUPPORTED = ['project', 'work_package'];
if (!SUPPORTED.includes(model)) return;
fetch(`/inplace_edit_fields?model=${model}&attribute=name`) Defensive patterns
Strategy: validation
Validate before calling
klass = OpenProject::InplaceEdit::UpdateRegistry.resolve_model_class(params[:model]) return head :not_found unless klass && klass < ApplicationRecord && klass.respond_to?(:visible)
Type guard
def inplace_model?(param) klass = OpenProject::InplaceEdit::UpdateRegistry.resolve_model_class(param) !klass.nil? && klass < ApplicationRecord && klass.respond_to?(:visible) end
Try / catch
begin resolve_model_class(params[:model]) rescue ArgumentError head :not_found end
Prevention
- Drive the frontend model list from the registry keys instead of a duplicated hardcoded list.
- Never broaden resolve_model_class to arbitrary constantize — the whitelist is the security boundary.
- When adding a model, register it first, then ship the UI that requests it.
When it happens
Trigger: GET/POST /inplace_edit_fields with model=<class not in the registry> — e.g. 'user', 'milestone' or a misspelled value — or a registered class that fails the ApplicationRecord/.visible checks.
Common situations: Frontend code updated to offer inline edit on a new model before the backend registered it; stale JS requesting a model removed from the registry; a fork adding a non-AR model (plain class) to the registry.
Related errors
- Invalid step: #{step}
- Missing update handler for #{@model}
- Missing relation_type parameter
- Invalid relation type: #{type}
AI-assisted analysis of opf/openproject@d9742c43f3 (2026-08-21).
Data as JSON: /api/errors/20ad34bf70521071.
Report an issue: GitHub.