instructure/canvas-lms · error
conversation_ids needs to be scoped to a user
Error message
conversation_ids needs to be scoped to a user
What it means
ConversationParticipant.conversation_ids is designed as a scope-chaining helper that requires the relation be scoped to a specific user_id. It introspects the relation's WHERE predicates and raises if none constrain user_id, because running it unscoped would leak conversation IDs across users.
Solutions
- Scope the relation to a user first: user.conversation_participants.conversation_ids or ConversationParticipant.where(user_id: user).conversation_ids
- Reorder scope chaining so where(user_id:) is applied before calling conversation_ids
- In the regex-compatible path, a raw SQL string predicate like 'user_id = 5' also satisfies the check
Example fix
// before ConversationParticipant.conversation_ids // after ConversationParticipant.where(user_id: user).conversation_ids
Defensive patterns
Strategy: validation
Validate before calling
raise 'scope to a user first' unless relation.where_clause Predicates inspect — simply always build as ConversationParticipant.where(user_id: user).conversation_ids
Type guard
null
Try / catch
null
Prevention
- Never call class-level ConversationParticipant.conversation_ids directly
- Chain user scoping before any relation-consuming helper
- Prefer user.conversation_participants for user-scoped queries
When it happens
Trigger: Calling ConversationParticipant.conversation_ids on a relation without a where(user_id: ...) clause, e.g. ConversationParticipant.conversation_ids directly, or after chaining only non-user predicates (workflow_state, etc.).
Common situations: Refactoring code that dropped the user scope; building ad-hoc console/admin queries without scoping; composing scopes where the user_id condition is applied later than this call.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- top_enrollment_by_user must be scoped
- An institutional tag category did not pass validation
- assessor and assessee required
- association required
- can only forward one conversation at a time
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/3f33f5d197c1b04a.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/conversation_participant.rb:556
@last_message ||= messages.human.first if last_message_at
end
attr_writer :last_authored_message
def last_authored_message
@last_authored_message ||= conversation.shard.activate { messages.human.by_user(user_id).first } if visible_last_authored_at
end
def self.preload_latest_messages(conversations, author)
# preload last_message
ConversationMessage.preload_latest conversations.select(&:last_message_at)
# preload last_authored_message
ConversationMessage.preload_latest conversations.select(&:visible_last_authored_at), author
end
def self.conversation_ids
where_predicates = all.where_clause.instance_variable_get(:@predicates)
raise "conversation_ids needs to be scoped to a user" unless where_predicates.any? do |v|
if v.is_a?(Arel::Nodes::Binary) && v.left.is_a?(Arel::Attributes::Attribute)
v.left.name == "user_id"
else
v =~ /user_id (?:= |IN \()\d+/
end
end
order = "last_message_at DESC" unless all.order_values.present?
self.order(order).pluck(:conversation_id)
end
def self.users_by_conversation_shard(user_ids)
{ Shard.current => user_ids }
end
def update_one(update_params)
case update_params[:event]
View on GitHub (pinned to 1c9f0bb801)