instructure/canvas-lms · error · GraphQL::ExecutionError
filter must be one of: #
Error message
filter must be one of: #{VALID_ANNOUNCEMENT_FILTERS.join(", ")} What it means
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.
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
Example fix
// before
filters: { "filter": "Unread" }
// after
filters: { "filter": "unread" } Defensive patterns
Strategy: validation
Validate before calling
const VALID = ["unread", "read", "all"];
if (filters.filter !== undefined && !(typeof filters.filter === "string" && VALID.includes(filters.filter))) {
throw new Error(`filter must be one of: ${VALID.join(", ")}`);
} Type guard
const isAnnouncementFilter = (v) => typeof v === "string" && ["unread","read","all"].includes(v);
Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- filter must be one of: #
- selectedDateFilter must be one of: #
- A maximum of 50 assessees can be provided at once
- A maximum of 50 assessors can be provided at once
- All ConversationMessages must exist within the same…
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/5e5ac31053ce40a9.
Report an issue: GitHub.
Appendix: source
Thrown at app/graphql/mutations/update_widget_dashboard_config.rb:102
end
def validate_filter_structure!(widget_id, filters)
if widget_id == ANNOUNCEMENTS_WIDGET_ID
validate_announcements_filters!(filters)
elsif widget_id == TODO_LIST_WIDGET_ID
validate_todo_list_filters!(filters)
elsif COURSE_WORK_WIDGET_IDS.include?(widget_id)
validate_course_work_filters!(filters)
else
validate_generic_filters!(filters)
end
end
def validate_announcements_filters!(filters)
if filters.key?("filter")
filter_value = filters["filter"]
unless filter_value.is_a?(String) && VALID_ANNOUNCEMENT_FILTERS.include?(filter_value)
raise GraphQL::ExecutionError, "filter must be one of: #{VALID_ANNOUNCEMENT_FILTERS.join(", ")}"
end
end
invalid_keys = filters.keys - ["filter"]
unless invalid_keys.empty?
raise GraphQL::ExecutionError, "invalid filter keys for announcements widget: #{invalid_keys.join(", ")}"
end
end
def validate_todo_list_filters!(filters)
if filters.key?("filter")
filter_value = filters["filter"]
unless filter_value.is_a?(String) && VALID_TODO_FILTERS.include?(filter_value)
raise GraphQL::ExecutionError, "filter must be one of: #{VALID_TODO_FILTERS.join(", ")}"
end
end
invalid_keys = filters.keys - ["filter"]View on GitHub (pinned to 1c9f0bb801)