{"record":{"id":"310ab0606e0baa1f","repo":"opf/openproject","slug":"invalid-cf-type","errorCode":null,"errorMessage":"Invalid CF type","messagePattern":"Invalid CF type","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"app/services/custom_fields/create_service.rb","lineNumber":51,"sourceCode":"    def self.careful_new_custom_field(type)\n      if /.+CustomField\\z/.match?(type.to_s)\n        klass = type.to_s.constantize\n        klass.new if klass.ancestors.include? CustomField\n      end\n    rescue NameError => e\n      Rails.logger.error \"#{e.message}:\\n#{e.backtrace.join(\"\\n\")}\"\n      nil\n    end\n\n    def perform\n      super\n    rescue StandardError => e\n      ServiceResult.failure(message: e.message)\n    end\n\n    def instance(params)\n      cf = self.class.careful_new_custom_field(params[:type])\n      raise ArgumentError.new(\"Invalid CF type\") unless cf\n\n      cf\n    end\n\n    def after_perform(call)\n      cf = call.result\n\n      if cf.field_format_calculated_value? && cf.is_required?\n        enqueue_recalculate_values(cf)\n      end\n\n      if cf.hierarchical_list?\n        CustomFields::Hierarchy::HierarchicalItemService.new.generate_root(cf)\n      end\n\n      call\n    end\n","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/opf/openproject/blob/d9742c43f3424c34b63550f8c03f201fe5c3040c/app/services/custom_fields/create_service.rb#L33-L69","documentation":"CustomFields::CreateService#instance builds the new record via careful_new_custom_field(params[:type]), which constantizes the STI type string and returns nil when it does not resolve to a loadable CustomField subclass. When nil, the service raises ArgumentError('Invalid CF type') before any validation runs. Valid values are concrete class names like 'WorkPackageCustomField', 'ProjectCustomField', 'UserCustomField'.","triggerScenarios":"Calling CustomFields::CreateService.new(user: u).call(type: 'FooCustomField', ...) or type: 'WorkPackageCustomFieldXX' — any type string that is not a name of a loaded CustomField descendant.","commonSituations":"A plugin that defined a custom field subclass was removed, so re-importing or re-running seeds that reference its type now fails; an API client sends a made-up or misspelled type; a core upgrade renamed/moved an STI class.","solutions":["Pass an exact built-in type: 'WorkPackageCustomField', 'ProjectCustomField', 'UserCustomField', 'TimeLineCustomField' etc. — check CustomField.descendants.map(&:name) in console for the supported list.","If the type came from a plugin, restore/install the plugin that defines that class before creating the field.","Validate the incoming type server-side before calling the service (see validation code) so the failure is a 4xx, not an ArgumentError."],"exampleFix":"# before\nCustomFields::CreateService.new(user: user).call(type: 'FooCustomField', name: 'X', field_format: 'string')\n\n# after\nunless CustomField.descendants.map(&:name).include?('FooCustomField')\n  return ServiceResult.failure(message: 'Unknown custom field type FooCustomField')\nend\nCustomFields::CreateService.new(user: user).call(type: 'FooCustomField', name: 'X', field_format: 'string')","handlingStrategy":"validation","validationCode":"valid_types = CustomField.descendants.map(&:name)\nraise ArgumentError, \"Unknown custom field type #{params[:type]}\" unless valid_types.include?(params[:type].to_s)","typeGuard":"def custom_field_type?(value)\n  value.is_a?(String) && CustomField.descendants.map(&:name).include?(value)\nend","tryCatchPattern":"begin\n  CustomFields::CreateService.new(user: user).call(**params)\nrescue ArgumentError => e\n  ServiceResult.failure(message: e.message)\nend","preventionTips":["Derive type dynamically from CustomField.descendants instead of hardcoding a list that goes stale.","Treat unregistered plugin field types as configuration drift: validate before the import run starts, not mid-job.","Pin plugin load order so STI subclasses exist before seeds/imports run."],"tags":["custom-fields","activerecord","sti","service-object","validation"],"backgroundTag":"unknown-sti-class","analyzedSha":"d9742c43f3424c34b63550f8c03f201fe5c3040c","analyzedAt":"2026-08-21T14:40:06.829Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}