instructure/canvas-lms · error · GraphQL::ExecutionError
filter must be one of: #
Error message
filter must be one of: #{VALID_TODO_FILTERS.join(", ")} What it means
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.
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
Example fix
// before
filters: { "filter": "incomplete" }
// after
filters: { "filter": "incomplete_items" } Defensive patterns
Strategy: validation
Validate before calling
const VALID = ["incomplete_items", "complete_items", "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 isTodoFilter = (v) => typeof v === "string" && ["incomplete_items","complete_items","all"].includes(v);
Prevention
- 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
When it happens
Trigger: Sending the UpdateWidgetDashboardConfig mutation for the todo list widget with filters["filter"] set to e.g. "incomplete", "todo", "open_items", 0, or null.
Common situations: 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.
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/b280a3b6970a38bb.
Report an issue: GitHub.
Appendix: source
Thrown at app/graphql/mutations/update_widget_dashboard_config.rb:116
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"]
unless invalid_keys.empty?
raise GraphQL::ExecutionError, "invalid filter keys for todo list widget: #{invalid_keys.join(", ")}"
end
end
def validate_course_work_filters!(filters)
if filters.key?("selectedCourse")
course_value = filters["selectedCourse"]
unless course_value.is_a?(String) && (course_value == "all" || course_value.match?(/^course_\d+$/))
raise GraphQL::ExecutionError, "selectedCourse must be 'all' or 'course_{id}'"
end
end
if filters.key?("selectedDateFilter")View on GitHub (pinned to 1c9f0bb801)