{"record":{"id":"b280a3b6970a38bb","repo":"instructure/canvas-lms","slug":"filter-must-be-one-of-valid-todo-filters-join","errorCode":null,"errorMessage":"filter must be one of: #{VALID_TODO_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":116,"sourceCode":"  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\"]\n    unless invalid_keys.empty?\n      raise GraphQL::ExecutionError, \"invalid filter keys for todo list widget: #{invalid_keys.join(\", \")}\"\n    end\n  end\n\n  def validate_course_work_filters!(filters)\n    if filters.key?(\"selectedCourse\")\n      course_value = filters[\"selectedCourse\"]\n      unless course_value.is_a?(String) && (course_value == \"all\" || course_value.match?(/^course_\\d+$/))\n        raise GraphQL::ExecutionError, \"selectedCourse must be 'all' or 'course_{id}'\"\n      end\n    end\n\n    if filters.key?(\"selectedDateFilter\")","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/update_widget_dashboard_config.rb#L98-L134","documentation":"The todo list widget's filter hash, if it contains a \"filter\" key, must be a String in VALID_TODO_FILTERS (\"incomplete_items\", \"complete_items\", \"all\"). validate_todo_list_filters! raises this GraphQL::ExecutionError for any other value or non-string type.","triggerScenarios":"Sending the UpdateWidgetDashboardConfig mutation for the todo list widget with filters[\"filter\"] set to e.g. \"incomplete\", \"todo\", \"open_items\", 0, or null.","commonSituations":"Front-end sending shortened or renamed variants of the allowed values; case sensitivity issues (\"Incomplete_Items\"); stale client code from before the filter vocabulary was defined.","solutions":["Use exactly one of \"incomplete_items\", \"complete_items\", or \"all\"","Check VALID_TODO_FILTERS in app/graphql/mutations/update_widget_dashboard_config.rb for the canonical values","Map client-side state to the allowed enum before sending"],"exampleFix":"// before\nfilters: { \"filter\": \"incomplete\" }\n// after\nfilters: { \"filter\": \"incomplete_items\" }","handlingStrategy":"validation","validationCode":"const VALID = [\"incomplete_items\", \"complete_items\", \"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 isTodoFilter = (v) => typeof v === \"string\" && [\"incomplete_items\",\"complete_items\",\"all\"].includes(v);","tryCatchPattern":null,"preventionTips":["Mirror VALID_TODO_FILTERS in a shared constant on the client","Map UI labels to exact enum strings before sending","Never construct filter values by free text"],"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"}