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

Must be logged in

Error message

Must be logged in

What it means

Raised in the RejectEnrollmentInvitation mutation when context[:current_user] is nil, meaning the GraphQL request is unauthenticated. The mutation refuses to proceed without a logged-in user before doing any enrollment lookup.

Solutions

  1. Authenticate the request: ensure a valid Canvas session cookie or Bearer access token is sent with the GraphQL call
  2. Refresh an expired session (re-login) before retrying
  3. For scripts, generate a developer-key/token and pass it in the Authorization header
  4. Check the client redirects to login when current_user is nil

Example fix

// before
fetch('/api/graphql', { method: 'POST', body }) // no auth
// after
fetch('/api/graphql', { method: 'POST', headers: { Authorization: `Bearer ${token}` }, body })
Defensive patterns

Strategy: try-catch

Validate before calling

if (!currentUser) redirectToLogin()

Type guard

function isAuthenticated(ctx) { return Boolean(ctx?.currentUser?.id) }

Try / catch

try {
  await rejectEnrollmentInvitation({ enrollmentUuid })
} catch (e) {
  if (e.message.includes('Must be logged in')) { redirectToLogin(); return }
  throw e
}

Prevention

When it happens

Trigger: Calling rejectEnrollmentInvitation without a valid session or access token; expired Canvas session; API token omitted/invalid on the GraphQL endpoint.

Common situations: Deep-linking a user to an invitation-action page after their session expired; server-side scripts calling the GraphQL endpoint without Authorization header; cookies blocked or cleared.

Related errors


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

Appendix: source

Thrown at app/graphql/mutations/reject_enrollment_invitation.rb:30

# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#

module Mutations
  class RejectEnrollmentInvitation < BaseMutation
    argument :enrollment_uuid, String, required: true

    field :enrollment, Types::EnrollmentType, null: true
    field :success, Boolean, null: false

    def resolve(input:, **)
      user = context[:current_user]
      raise GraphQL::ExecutionError, I18n.t("Must be logged in") unless user

      enrollment = Enrollment.where(uuid: input[:enrollment_uuid]).first
      raise GraphQL::ExecutionError, I18n.t("Enrollment invitation not found") unless enrollment

      # Verify the enrollment belongs to the current user
      raise GraphQL::ExecutionError, I18n.t("Unauthorized") unless enrollment.user == user

      # Verify the enrollment is in invited state
      raise GraphQL::ExecutionError, I18n.t("Enrollment is not in invited state") unless enrollment.invited?

      begin
        if enrollment.reject
          {
            enrollment:,
            success: true
          }
        else
          {

View on GitHub (pinned to 1c9f0bb801)