heartcombo/devise · error · NotImplementedError

"Devise doesn't know how to sanitize parameters for '#

Error message

"Devise doesn't know how to sanitize parameters for '#{action}'".
If you want to define a new set of parameters to be sanitized use the
`permit` method first:

  devise_parameter_sanitizer.permit(:#{action}, keys: [:param1, :param2, :param3])

What it means

Devise::ParameterSanitizer whitelists request parameters per action; defaults are pre-registered only for :sign_in, :sign_up and :account_update (DEFAULT_PERMITTED_ATTRIBUTES). sanitize(action) looks up @permitted[action] and, when nothing was registered for that action (no array and no block), calls unknown_action!, which raises NotImplementedError with instructions to call permit first. It fires whenever you sanitize an action whose permission list was never declared.

Solutions

  1. Register the permission list before sanitizing, typically in a before_action: devise_parameter_sanitizer.permit(:accept_invitation, keys: [:invitation_token, :name, :password, :password_confirmation]).
  2. For nested/full control, use the block form: devise_parameter_sanitizer.permit(:accept_invitation) { |u| u.permit(:invitation_token, profile: [:name]) }.
  3. If the action is really one of the standard ones, fix the symbol: sanitize(:sign_up) not sanitize(:signup) — and make sure the permit and sanitize calls use the identical symbol.
  4. Ensure your before_action configure_permitted_parameters runs before the action that sanitizes (declared in ApplicationController with if: :devise_controller?).

Example fix

# before (custom Devise controller)
class Users::InvitationsController < Devise::RegistrationsController
  def update
    self.resource = resource_class.accept_invitation(
      devise_parameter_sanitizer.sanitize(:accept_invitation) # NotImplementedError
    )
  end
end

# after
class Users::InvitationsController < Devise::RegistrationsController
  before_action :configure_invitation_params, only: :update

  def update
    self.resource = resource_class.accept_invitation(
      devise_parameter_sanitizer.sanitize(:accept_invitation)
    )
  end

  protected

  def configure_invitation_params
    devise_parameter_sanitizer.permit(
      :accept_invitation,
      keys: [:invitation_token, :password, :password_confirmation]
    )
  end
end
Defensive patterns

Strategy: validation

Validate before calling

# Register every custom action's permissions before any sanitize call:
class Users::InvitationsController < Devise::RegistrationsController
  CUSTOM_SANITIZED_ACTIONS = %i(accept_invitation).freeze

  before_action only: :update do
    devise_parameter_sanitizer.permit(
      :accept_invitation,
      keys: [:invitation_token, :password, :password_confirmation]
    )
  end
end

# If you must check before calling sanitize (introspects the private registry):
def sanitizer_registered?(action)
  devise_parameter_sanitizer
    .instance_variable_get(:@permitted)
    .key?(action.to_sym)
end

Type guard

def sanitizable_action?(sanitizer, action)
  sanitizer.instance_variable_get(:@permitted).key?(action.to_sym)
end
# usage: params = sanitizer.sanitize(action) if sanitizable_action?(sanitizer, :accept_invitation)

Try / catch

# Around a custom sanitize call in code you don't fully control:
begin
  attrs = devise_parameter_sanitizer.sanitize(:accept_invitation)
rescue NotImplementedError
  devise_parameter_sanitizer.permit(:accept_invitation, keys: [:invitation_token, :password, :password_confirmation])
  attrs = devise_parameter_sanitizer.sanitize(:accept_invitation)
end

Prevention

When it happens

Trigger: A custom Devise controller action calling devise_parameter_sanitizer.sanitize(:accept_invitation) (or any symbol outside sign_in/sign_up/account_update) without a matching devise_parameter_sanitizer.permit(:accept_invitation, keys: [...]) beforehand; a typo making the permit and sanitize symbols differ (permit(:signip) vs sanitize(:sign_in)); code migrated from the old Devise 2.x/3.x sanitizer API that had different default actions.

Common situations: Building custom registration or invitation flows on Devise controllers; overriding Devise::RegistrationsController#create and sanitizing a custom action name; large apps that whitelist extra profile fields per action and miss one; refactoring renames an action symbol in one place but not the other.

Related errors


AI-assisted analysis of heartcombo/devise@372b295fe6 (2026-08-21). Data as JSON: /api/errors/db9a980a04707990. Report an issue: GitHub.

Appendix: source

Thrown at lib/devise/parameter_sanitizer.rb:163

      @params[@resource_name].respond_to?(:permit)
    end

    def empty_params
      ActionController::Parameters.new({})
    end

    def permit_keys(parameters, keys)
      parameters.permit(*keys)
    end

    def extract_auth_keys(klass)
      auth_keys = klass.authentication_keys

      auth_keys.respond_to?(:keys) ? auth_keys.keys : auth_keys
    end

    def unknown_action!(action)
      raise NotImplementedError, <<-MESSAGE.strip_heredoc
        "Devise doesn't know how to sanitize parameters for '#{action}'".
        If you want to define a new set of parameters to be sanitized use the
        `permit` method first:

          devise_parameter_sanitizer.permit(:#{action}, keys: [:param1, :param2, :param3])
      MESSAGE
    end
  end
end

View on GitHub (pinned to 372b295fe6)