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
- Inspect the submission/assessment row: fix or backfill user_id if the data is corrupt.
- Pass an explicit rubric_assessment_id only when the assessment actually has a user.
- 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
- Backfill nil user_id on legacy submissions
- Skip rubric assessment for anonymous/external submissions without users
- Log submission.user_id anomalies during data migrations
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
- Assignment Grade Error
- e.message (Assignment::MaxGradersReachedError)
- Not authorized to assess user
- Rubric not found: #
- Submission not found
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)