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

  1. Only request inplace edits for models registered in OpenProject::InplaceEdit::UpdateRegistry (list keys in console).
  2. If a legitimate model is missing, register it with handler and contract so it passes both resolve_model_class and invoke_update_handler.
  3. 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

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


AI-assisted analysis of opf/openproject@d9742c43f3 (2026-08-21). Data as JSON: /api/errors/20ad34bf70521071. Report an issue: GitHub.