instructure/canvas-lms · error · GraphQL::ExecutionError
You do not have permission to view this course.
Error message
You do not have permission to view this course.
What it means
discussions_scope in discussions_connection_interface.rb raises this GraphQL::ExecutionError when the current user is not allowed to view discussions on behalf of the requested scoped user. The permission check delegates to current_user.can_current_user_view_as_user(course, scoped_user), which fails unless the viewer is the scoped user or an admin permitted to 'view as' that user in the course. It is a masquerade-style authorization guard, not a general read-permission check.
Solutions
- Remove the user_id argument (or pass the current user's own id) so the scope targets the caller itself.
- Log in as, or use a token for, the user whose discussions you need.
- Use an account-level admin token with 'View as' permission over the target user.
- Check can_current_user_view_as_user(course, scoped_user) client-side before adding user_id to the query.
- If user_id was intentionally passed but the user is missing, note that a nil scoped_user already returns DiscussionTopic.none — only valid user_ids are permission-checked.
Example fix
// before
query { course(id: 1) { discussionsConnection(userId: 42) { nodes { id } } } }
// after
query { course(id: 1) { discussionsConnection { nodes { id } } } } // omit userId, or pass your own id Defensive patterns
Strategy: validation
Validate before calling
// before sending the query
const canViewAs = (course, targetUserId, currentUserId, isAdmin) =>
targetUserId === undefined || targetUserId === currentUserId || isAdmin
if (!canViewAs(course, variables.userId, currentUser.id, currentUser.admin))
throw new Error("user_id not viewable by current user; omit userId or use admin token") Type guard
const isOwnScope = (v) => v.userId === undefined || v.userId === currentUser.id
Prevention
- Only pass user_id when impersonation ('view as') is genuinely intended
- Reuse one auth token per user identity in tooling
- Check role/admin status before masquerading queries
- Strip user_id from shared query templates
When it happens
Trigger: Querying legacyNode/course.discussionsConnection (discussions_connection) with a user_id argument for a user the caller is not allowed to view as — e.g. a student supplying another student's user_id, or a teacher without 'view as' rights targeting an admin.
Common situations: Developers testing the GraphQL API with a hard-coded user_id belonging to a different account; tooling that caches one user's token while querying another user's discussions; admins operating in a sub-account where 'View as' is restricted.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- You do not have permission to view this course.
- You do not have permission to view this course.
- insufficient permission
- insufficient permission
- insufficient permission
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/c0b56aea5205937d.
Report an issue: GitHub.
Appendix: source
Thrown at app/graphql/interfaces/discussions_connection_interface.rb:46
argument :search_term, String, <<~MD, required: false
only return discussions whose title matches this search term
MD
argument :is_announcement, Boolean, <<~MD, required: false
only return discussions that are announcements (true) or
regular discussions (false). If not provided, returns both.
MD
end
def discussions_scope(course, user_id = nil, search_term = nil, is_announcement = nil)
scoped_user = user_id.nil? ? current_user : User.find_by(id: user_id)
# If user_id was provided but user not found, return no discussions
return DiscussionTopic.none if user_id.present? && scoped_user.nil?
# Check if current user has permission to view discussions as the scoped user
unless current_user.can_current_user_view_as_user(course, scoped_user)
# Current user lacks permissions to view as the scoped user
raise GraphQL::ExecutionError, "You do not have permission to view this course."
end
discussions = if is_announcement == true
# For announcements, use the same logic as /courses/X/announcements page
# Start with active_announcements scope (just workflow_state <> 'deleted')
course.active_announcements
else
course.discussion_topics.active
end
# Apply announcement filter for non-announcement-specific queries
if is_announcement == false
discussions = discussions.where(type: ["DiscussionTopic", nil])
end
# Apply search term filter if provided
if search_term.present?
discussions = discussions.where(DiscussionTopic.wildcard(:title, search_term))View on GitHub (pinned to 1c9f0bb801)