{"record":{"id":"162a932e31cdb88f","repo":"instructure/canvas-lms","slug":"invalid-filter-keys-for-announcements-widget-invalid-keys","errorCode":null,"errorMessage":"invalid filter keys for announcements widget: #{invalid_keys.join(\", \")}","messagePattern":"invalid filter keys for announcements widget: #(.+?)","errorType":"validation","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/update_widget_dashboard_config.rb","lineNumber":108,"sourceCode":"      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\"]\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)","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/update_widget_dashboard_config.rb#L90-L126","documentation":"The announcements widget filter hash only permits a single key, \"filter\". validate_announcements_filters! computes filters.keys - [\"filter\"] and raises this GraphQL::ExecutionError if any unexpected keys are present, protecting the stored widget config from unknown/typo'd fields.","triggerScenarios":"Sending a mutation for the announcements widget with filters containing any key besides \"filter\" (e.g. {\"unreadOnly\": true}, {\"filter\": \"all\", \"sort\": \"date\"}).","commonSituations":"Front-end code copy-pasted from another widget (course work uses selectedCourse/selectedDateFilter); adding a new filter key without updating the server-side whitelist; misspelled key names like \"fitler\".","solutions":["Remove the extraneous keys so the announcements filters hash contains only \"filter\"","If a new filter option is genuinely needed, add it to the allowed-keys subtraction in validate_announcements_filters! and persist it safely","Confirm which widget you are targeting; other widgets allow different keys"],"exampleFix":"// before\nfilters: { \"filter\": \"all\", \"sort\": \"date\" }\n// after\nfilters: { \"filter\": \"all\" }","handlingStrategy":"validation","validationCode":"const allowedKeys = [\"filter\"];\nconst invalid = Object.keys(filters).filter((k) => !allowedKeys.includes(k));\nif (invalid.length) throw new Error(`invalid filter keys for announcements widget: ${invalid.join(\", \")}`);","typeGuard":"const hasOnlyFilterKey = (f) => f && Object.keys(f).every((k) => k === \"filter\");","tryCatchPattern":null,"preventionTips":["Use per-widget filter type definitions so wrong keys fail at compile time","Do not reuse filter objects across widget types","Strip unknown keys from UI state before persisting"],"tags":["graphql","validation","unknown-key"],"backgroundTag":"invalid-argument-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"}