instructure/canvas-lms · error · GraphQL::ExecutionError

Not authorized to view this user's module progress

Error message

Not authorized to view this user's module progress

What it means

apply_module_filters determines the target user (from filter user_id or the current user) and checks can_view_user_module_progress? before applying Modules::FilterByCompletion. If the requesting user lacks permission to view that target user's progress, it raises 'Not authorized to view this user's module progress'.

Solutions

  1. Query only your own module progress (omit user_id) unless you are a permitted observer/teacher
  2. Verify the user_id global ID is correct and belongs to the same course
  3. Check the enrolling user as an observer if viewing a student's progress
  4. Confirm course-level permissions (teacher/admin) before filtering on another user

Example fix

// before
modules(filter: { completionStatus: "incomplete", userId: classmateGid })
// after
modules(filter: { completionStatus: "incomplete" })  // own progress only
Defensive patterns

Strategy: try-catch

Validate before calling

const isSelf = targetUserId === currentUser.id
const isPermittedObserver = currentUser.observerOf?.includes(targetUserId)
const isTeacher = currentUser.enrollments?.some(e => e.type === 'TeacherEnrollment' && e.courseId === courseId)
if (!(isSelf || isPermittedObserver || isTeacher)) omitUserIdFilter()

Type guard

function canViewProgress(me, target, courseId) { return me?.id === target || me?.observerOf?.includes(target) || me?.enrollments?.some(e => e.type === 'TeacherEnrollment' && e.courseId === courseId) }

Try / catch

try { await query(MODULES_QUERY) } catch (e) { if (e.message.startsWith('Not authorized')) { fallBackToOwnProgress() } }

Prevention

When it happens

Trigger: Querying course.modules with filter.completion_status for a user_id the current user is not allowed to observe (not self, not an observer/student of that user, not a teacher in the course).

Common situations: Observer/parent tooling querying the wrong user id; students attempting to view classmates' progress; stale or global-id mismatch causing the permission lookup to fail.

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


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/287ffc79cfe8a076. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/types/course_type.rb:741

          # For unauthenticated users, only "incomplete" filter returns modules
          # All other filters return empty since they have no progress
          case filter[:completion_status]
          when "incomplete"
            return scope # All modules are incomplete for unauthenticated users
          else
            return scope.none # No completed/in_progress/not_started modules
          end
        end

        target_user = if filter[:user_id]
                        User.find(filter[:user_id])
                      else
                        current_user
                      end

        # Check permissions before applying filter
        unless can_view_user_module_progress?(target_user)
          raise GraphQL::ExecutionError, "Not authorized to view this user's module progress"
        end

        scope = Modules::FilterByCompletion.new(
          scope,
          filter[:completion_status],
          target_user,
          current_user,
          course
        ).filter
      end

      scope
    end

    def can_view_user_module_progress?(user)
      # Users can always view their own progress
      return true if user.id == current_user.id

View on GitHub (pinned to 1c9f0bb801)