{"record":{"id":"691324d6a2c09d14","repo":"instructure/canvas-lms","slug":"improper-status-for-user-user-user-id","errorCode":null,"errorMessage":"Improper status for user #{user.user_id}","messagePattern":"Improper status for user #(.+?)","errorType":"validation","errorClass":"ImportError","httpStatus":null,"severity":"error","filePath":"lib/sis/user_importer.rb","lineNumber":78,"sourceCode":"        @batched_users = []\n        @messages = messages\n        @success_count = 0\n\n        @roll_back_data = []\n        @users_to_set_sis_batch_ids = []\n        @pseudos_to_set_sis_batch_ids = []\n        @users_to_add_account_associations = []\n        @users_to_update_account_associations = []\n        @users_to_sync = Set.new\n        @authentication_providers = {}\n      end\n\n      # Pass a single instance of SIS::Models::User\n      def add_user(user, login_only: false)\n        raise ImportError, \"No user_id given for a user\" if user.user_id.blank?\n        raise ImportError, \"No login_id given for user #{user.user_id}\" if user.login_id.blank?\n        raise ImportError, \"No status given for user #{user.user_id}\" if user.status.blank?\n        raise ImportError, \"Improper status for user #{user.user_id}\" unless user.status.match?(/\\A(active|suspended|deleted)/i)\n        return if @batch.skip_deletes? && user.status.match?(/deleted/i)\n\n        if login_only && user.existing_user_id.blank? && user.existing_integration_id.blank? && user.existing_canvas_user_id.blank?\n          raise ImportError, I18n.t(\"No existing user provided for login with SIS ID %{user_id}\", user_id: user.user_id)\n        end\n\n        @batched_users << user\n        process_batch(login_only:) if @batched_users.size >= BATCH_SIZE\n      end\n\n      def any_left_to_process?\n        !@batched_users.empty?\n      end\n\n      def infer_user_name(user_row, prior_name = nil)\n        if user_row.full_name.present?\n          user_row.full_name\n        elsif user_row.first_name.present? || user_row.last_name.present?","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/sis/user_importer.rb#L60-L96","documentation":"add_user only accepts statuses beginning with active, suspended, or deleted (case-insensitive). Any other string — typos, alternate vocabularies like 'inactive' or 'enabled' — is rejected with this ImportError, since Canvas SIS imports have a fixed status vocabulary.","triggerScenarios":"add_user with user.status like 'inactive', 'enabled', 'archived', or a localized/translated status word that does not match /\\A(active|suspended|deleted)/i.","commonSituations":"Mapping another system's status vocabulary (e.g. HR 'inactive') directly into the SIS import; whitespace or translation issues in exports; someone setting 'deleted!' or 'deactivated' expecting it to work.","solutions":["Map source statuses to the exact Canvas vocabulary: active, suspended, deleted","Strip/normalize the status string (downcase, trim) before building the Models::User","Treat unrecognized statuses as 'active' only after confirming that matches your policy","Log and skip rows with unmappable statuses"],"exampleFix":"// before\nuser = Sis::Models::User.new(user_id: id, login_id: login, status: hr_status) # e.g. 'inactive'\n// after\nmapped = { 'active' => 'active', 'enabled' => 'active', 'inactive' => 'suspended', 'terminated' => 'deleted' }.fetch(hr_status.downcase.strip, nil)\nraise ArgumentError, \"unmapped status #{hr_status}\" unless mapped\nuser = Sis::Models::User.new(user_id: id, login_id: login, status: mapped)","handlingStrategy":"validation","validationCode":"unless user.status.match?(/\\A(active|suspended|deleted)/i)\n  user.status = STATUS_MAP.fetch(user.status.to_s.downcase.strip, 'active')\nend","typeGuard":"VALID_STATUSES = %w[active suspended deleted].freeze\ndef valid_status?(u)\n  u.is_a?(Sis::Models::User) && VALID_STATUSES.any? { |s| u.status.to_s.downcase.start_with?(s) }\nend","tryCatchPattern":"begin\n  importer.add_user(user)\nrescue SisImports::ImportError => e\n  unmappable << user.user_id\nend","preventionTips":["Normalize and map external status vocabularies to active/suspended/deleted at ETL time","Add an allowlist assertion before building Models::User","Test with the full set of source-system status values"],"tags":["sis","import","enum","status"],"backgroundTag":"invalid-enum-value","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}