{"record":{"id":"5e5ac31053ce40a9","repo":"instructure/canvas-lms","slug":"filter-must-be-one-of-valid-announcement-filters-join","errorCode":null,"errorMessage":"filter must be one of: #{VALID_ANNOUNCEMENT_FILTERS.join(\", \")}","messagePattern":"filter must be one of: #(.+?)","errorType":"validation","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/update_widget_dashboard_config.rb","lineNumber":102,"sourceCode":"  end\n\n  def validate_filter_structure!(widget_id, filters)\n    if widget_id == ANNOUNCEMENTS_WIDGET_ID\n      validate_announcements_filters!(filters)\n    elsif widget_id == TODO_LIST_WIDGET_ID\n      validate_todo_list_filters!(filters)\n    elsif COURSE_WORK_WIDGET_IDS.include?(widget_id)\n      validate_course_work_filters!(filters)\n    else\n      validate_generic_filters!(filters)\n    end\n  end\n\n  def validate_announcements_filters!(filters)\n    if filters.key?(\"filter\")\n      filter_value = filters[\"filter\"]\n      unless filter_value.is_a?(String) && VALID_ANNOUNCEMENT_FILTERS.include?(filter_value)\n        raise GraphQL::ExecutionError, \"filter must be one of: #{VALID_ANNOUNCEMENT_FILTERS.join(\", \")}\"\n      end\n    end\n\n    invalid_keys = filters.keys - [\"filter\"]\n    unless invalid_keys.empty?\n      raise GraphQL::ExecutionError, \"invalid filter keys for announcements widget: #{invalid_keys.join(\", \")}\"\n    end\n  end\n\n  def validate_todo_list_filters!(filters)\n    if filters.key?(\"filter\")\n      filter_value = filters[\"filter\"]\n      unless filter_value.is_a?(String) && VALID_TODO_FILTERS.include?(filter_value)\n        raise GraphQL::ExecutionError, \"filter must be one of: #{VALID_TODO_FILTERS.join(\", \")}\"\n      end\n    end\n\n    invalid_keys = filters.keys - [\"filter\"]","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/update_widget_dashboard_config.rb#L84-L120","documentation":"UpdateWidgetDashboardConfig is a Canvas GraphQL mutation that saves dashboard widget configuration. When the announcements widget's filter hash contains a \"filter\" key, validate_announcements_filters! requires it to be a String listed in VALID_ANNOUNCEMENT_FILTERS (\"unread\", \"read\", \"all\"). Any other value or non-string type raises this GraphQL::ExecutionError, which surfaces as a GraphQL error on the mutation response.","triggerScenarios":"Sending a mutation with widget_id of the announcements widget and filters[\"filter\"] set to something other than \"unread\", \"read\", or \"all\" (e.g. \"unreads\", \"ALL\", \"everything\", a number, a boolean, or nil).","commonSituations":"Typos in filter names; front-end sending legacy or renamed filter values after a UI update; sending capitalized values when the check is case-sensitive; clients constructing filters from user input without mapping to the allowed set.","solutions":["Change the \"filter\" value to one of the allowed strings: \"unread\", \"read\", or \"all\"","Check the constant VALID_ANNOUNCEMENT_FILTERS in app/graphql/mutations/update_widget_dashboard_config.rb for the current allowed list","Normalize/mapping the client-side filter value (e.g. downcase, alias lookup) before sending the mutation","Validate the filter client-side before invoking the mutation"],"exampleFix":"// before\nfilters: { \"filter\": \"Unread\" }\n// after\nfilters: { \"filter\": \"unread\" }","handlingStrategy":"validation","validationCode":"const VALID = [\"unread\", \"read\", \"all\"];\nif (filters.filter !== undefined && !(typeof filters.filter === \"string\" && VALID.includes(filters.filter))) {\n  throw new Error(`filter must be one of: ${VALID.join(\", \")}`);\n}","typeGuard":"const isAnnouncementFilter = (v) => typeof v === \"string\" && [\"unread\",\"read\",\"all\"].includes(v);","tryCatchPattern":null,"preventionTips":["Keep a shared client-side enum mirroring VALID_ANNOUNCEMENT_FILTERS","Validate filter payloads in a shared helper before every dashboard config mutation","Watch for case sensitivity — values are matched exactly"],"tags":["graphql","validation","invalid-enum-value"],"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"}