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

User ID blank - unable to determine user for assessment

Error message

User ID blank - unable to determine user for assessment

What it means

The mutation needs a user_id to identify whose work is being assessed: from an existing rubric_assessment if rubric_assessment_id was supplied, otherwise from submission.user_id. It raises "User ID blank - unable to determine user for assessment" when that resolved user_id is nil/empty, which would break find_asset_for_assessment.

Solutions

  1. Inspect the submission/assessment row: fix or backfill user_id if the data is corrupt.
  2. Pass an explicit rubric_assessment_id only when the assessment actually has a user.
  3. For anonymous grading, confirm the feature path intended for anonymized submissions is used instead.

Example fix

// before
user_id = assessment.present? ? assessment.user_id : submission.user_id
raise GraphQL::ExecutionError, 'User ID blank - unable to determine user for assessment' if user_id.blank?
// after
user_id = assessment.present? ? assessment.user_id : submission.user_id
if user_id.blank?
  user_id = submission.original_user_id || submission.user&.id
  raise GraphQL::ExecutionError, 'User ID blank' if user_id.blank?
end
Defensive patterns

Strategy: validation

Validate before calling

// server-side guard before assess
raise GraphQL::ExecutionError, 'Submission has no user' if submission.user_id.blank? && input[:rubric_assessment_id].blank?

Type guard

def assessable_user_id?(submission) submission.user_id.present? end

Try / catch

try { await saveRubricAssessment(...) } catch (e) { if (e.message.includes('User ID blank')) showError('This submission cannot be assessed (no associated user)') }

Prevention

When it happens

Trigger: A submission row with a nil user_id (legacy/anonymous or corrupted data), or an existing assessment whose user_id is blank; passing rubric_assessment_id pointing at an anomalous assessment.

Common situations: Anonymous/moderated grading flows where submissions have no user; data migrated from older Canvas versions with null user ids; importing submissions from external tools.

Related errors


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

Appendix: source

Thrown at app/graphql/mutations/save_rubric_assessment.rb:46

  argument :submission_id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("Submission")

  field :rubric_assessment, Types::RubricAssessmentType, null: true
  field :rubric_association, Types::RubricAssociationType, null: true
  field :submission, Types::SubmissionType, null: true
  def resolve(input:)
    root_account = context[:domain_root_account]
    submission = Submission.find_by(id: input[:submission_id], root_account:)
    raise GraphQL::ExecutionError, "Submission not found" if submission.nil?

    association = RubricAssociation.find(input[:rubric_association_id])
    association_object = association.association_object

    assessment = association.rubric_assessments.find(input[:rubric_assessment_id]) if input[:rubric_assessment_id].present?

    # only check if there's no assessment object, since that's the only time
    # this param matters (find_asset_for_assessment)
    user_id = assessment.present? ? assessment.user_id : submission.user_id
    raise GraphQL::ExecutionError, "User ID blank - unable to determine user for assessment" if user_id.blank?

    # For a moderated assignment, submitting an assessment claims a grading
    # slot for the submitting provisional grader (or throws an error if no
    # slots remain).
    begin
      opts = {}
      provisional = input[:provisional]
      if provisional
        opts[:provisional_grader] = current_user
        if input[:final] && association_object.permits_moderation?(current_user)
          opts[:final] = true
        end
      end

      ensure_adjudication_possible(provisional:, association_object:, grader: current_user) do
        asset, user = association_object.find_asset_for_assessment(association, user_id, opts)
        assessment_details = JSON.parse(input[:assessment_details]).with_indifferent_access
        assessment_type = assessment_details[:assessment_type]

View on GitHub (pinned to 1c9f0bb801)