instructure/canvas-lms · error · ImportError

Can't remove yourself user_id '#

Error message

Can't remove yourself user_id '#{user_id}'

What it means

Raised by SIS::AdminImporter#process_admin when an import tries to delete (`status: 'deleted'`) an admin whose user is the same user running the batch, at the root account level. This self-protection prevents the import user from revoking their own admin privileges mid-import.

Solutions

  1. Remove the row (or change status to 'active') for the user running the import.
  2. Run the SIS import under a dedicated service/admin account not managed by the same CSV.
  3. Split the delete operation so the importing user's admin rights are removed manually by another admin.
  4. Filter the CSV before import to skip rows where user_id == batch user.

Example fix

// before
process_admin(user_id: 'sis-operator-1', account_id: 'root', role: 'AccountAdmin', status: 'deleted') // self-delete
// after
process_admin(user_id: 'other-admin-2', account_id: 'root', role: 'AccountAdmin', status: 'deleted')
Defensive patterns

Strategy: try-catch

Validate before calling

if status.to_s.downcase.strip == 'deleted' && user_id == batch_user_id && account_id == root_account_id
  raise ArgumentError, 'refusing to delete the importing admin from the root account'
end

Try / catch

begin
  importer.process_admin(user_id:, account_id:, role:, status: 'deleted')
rescue SIS::ImportError => e
  logger.warn("skipped self-delete: #{e.message}")
end

Prevention

When it happens

Trigger: Admin CSV row with status 'deleted' whose user_id equals @batch.user_id while @account equals @root_account — i.e. deleting the importing admin from the root account.

Common situations: Full admin syncs that regenerate the entire admin list and unintentionally omit the SIS operator's own membership; automation running under an admin account that is also managed by the same SIS feed.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/8a543d6e24f69850. Report an issue: GitHub.

Appendix: source

Thrown at lib/sis/admin_importer.rb:87

        return if @batch.skip_deletes? && state == "deleted"

        get_account(account_id)
        raise ImportError, "Invalid account_id given for admin" unless @account

        get_role(role_id, role)
        raise ImportError, "Invalid role '#{role}' for admin" if role.present? && !@role
        raise ImportError, "Invalid role_id '#{role_id}' for admin" if role_id.present? && !@role

        the_root_account = root_account_from_id(root_account) if root_account
        raise ImportError, "Invalid or unknown user_id '#{user_id}' for admin" if root_account && !the_root_account

        the_root_account ||= @root_account

        user = get_user(user_id, the_root_account)
        raise ImportError, "Invalid or unknown user_id '#{user_id}' for admin" unless user

        if state == "deleted" && user.id == @batch&.user_id && @account == @root_account
          raise ImportError, "Can't remove yourself user_id '#{user_id}'"
        end

        create_or_find_admin(user, state)
        user.clear_adminable_accounts_cache!
        @success_count += 1
      end

      def create_or_find_admin(user, state)
        case state
        when "active"
          admin = @account.account_users.where(user:, role: @role).first_or_initialize
          admin.workflow_state = state
        when "deleted"
          admin = @account.account_users.where(user:, role: @role).where.not(sis_batch_id: nil).take
          return unless admin

          admin.current_user = @batch.user if @batch&.user
          admin.workflow_state = state

View on GitHub (pinned to 1c9f0bb801)