instructure/canvas-lms · error

LLM generation is only available for rubrics associated…

Error message

LLM generation is only available for rubrics associated with an Assignment

What it means

validate_rubric_and_association_object requires the association_object passed to LLM criteria generation/regeneration to be an AbstractAssignment. LLM rubric generation depends on assignment context (description, points, grading type), so rubrics associated with non-assignment objects (quizzes, graded surveys, ungraded items) are rejected.

Solutions

  1. Ensure LLM generation is only invoked from the Assignment rubric editor (assignment must be an AbstractAssignment subclass instance).
  2. Check the association_object class in the controller and return a clear client error before reaching the service.
  3. If the feature must support other association types, extend the check or wrap the object in an assignment adapter — but do not bypass the guard.

Example fix

// before
RubricLlmService.new(rubric).generate_criteria_via_llm(association_object: quiz, ...)
// after
unless association_object.is_a?(AbstractAssignment)
  return render json: { error: 'LLM rubric generation is only available for assignments' }, status: :unprocessable_entity
end
RubricLlmService.new(rubric).generate_criteria_via_llm(association_object: association_object, ...)
Defensive patterns

Strategy: type-guard

Validate before calling

unless association_object.is_a?(AbstractAssignment)
  return render json: { error: 'AI rubric generation requires an assignment' }, status: :unprocessable_entity
end

Type guard

def assignment_context?(obj)
  obj.is_a?(AbstractAssignment)
end

Try / catch

begin
  service.generate_criteria_via_llm(...)
rescue RuntimeError => e
  raise unless e.message.include?('only available for rubrics associated with an Assignment')
  render json: { error: 'unsupported association type' }, status: :unprocessable_entity
end

Prevention

When it happens

Trigger: Calling generate_criteria_via_llm or regenerate_criteria_via_llm with an association_object that is a Quizzes::Quiz, a DiscussionTopic assignment-less association, a nil object, or any class not inheriting from AbstractAssignment.

Common situations: Rubric created for a quiz or a non-assignment context but the LLM generate button is wired to pass whatever association the page has; controllers pass raw association records of the wrong class; test code passes plain structs.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at app/services/rubric_llm_service.rb:191

  private

  def resolve_generate_options(generate_options)
    DEFAULT_GENERATE_OPTIONS.merge(generate_options.symbolize_keys)
  end

  def resolve_regenerate_options(generate_options, regenerate_options)
    resolved = resolve_generate_options(generate_options)
    resolved.merge(
      additional_user_prompt: regenerate_options.symbolize_keys[:additional_user_prompt].presence ||
                              resolved[:additional_prompt_info].presence ||
                              "No specific expectations, just improve it."
    )
  end

  def validate_rubric_and_association_object(association_object)
    unless association_object.is_a?(AbstractAssignment)
      raise "LLM generation is only available for rubrics associated with an Assignment"
    end
    raise "User must be associated to rubric before LLM generation" unless @rubric.user
  end

  def call_llm_with_prefill(llm_config, prompt, root_account_uuid)
    response = nil
    time = Benchmark.measure do
      response = CedarClient.conversation(
        messages:
         [{ role: "User", text: prompt },
          { role: "Assistant", text: "{" }],
        model: llm_config.model_id,
        feature_slug: GENERATE_FEATURE_SLUG,
        root_account_uuid:,
        current_user: @rubric.user
      ).response
    end
    [response, time]

View on GitHub (pinned to 1c9f0bb801)