{"record":{"id":"a8b467e428400b6f","repo":"instructure/canvas-lms","slug":"llm-generation-is-only-available-for-rubrics-associated-with","errorCode":null,"errorMessage":"LLM generation is only available for rubrics associated with an Assignment","messagePattern":"LLM generation is only available for rubrics associated with an Assignment","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/services/rubric_llm_service.rb","lineNumber":191,"sourceCode":"\n  private\n\n  def resolve_generate_options(generate_options)\n    DEFAULT_GENERATE_OPTIONS.merge(generate_options.symbolize_keys)\n  end\n\n  def resolve_regenerate_options(generate_options, regenerate_options)\n    resolved = resolve_generate_options(generate_options)\n    resolved.merge(\n      additional_user_prompt: regenerate_options.symbolize_keys[:additional_user_prompt].presence ||\n                              resolved[:additional_prompt_info].presence ||\n                              \"No specific expectations, just improve it.\"\n    )\n  end\n\n  def validate_rubric_and_association_object(association_object)\n    unless association_object.is_a?(AbstractAssignment)\n      raise \"LLM generation is only available for rubrics associated with an Assignment\"\n    end\n    raise \"User must be associated to rubric before LLM generation\" unless @rubric.user\n  end\n\n  def call_llm_with_prefill(llm_config, prompt, root_account_uuid)\n    response = nil\n    time = Benchmark.measure do\n      response = CedarClient.conversation(\n        messages:\n         [{ role: \"User\", text: prompt },\n          { role: \"Assistant\", text: \"{\" }],\n        model: llm_config.model_id,\n        feature_slug: GENERATE_FEATURE_SLUG,\n        root_account_uuid:,\n        current_user: @rubric.user\n      ).response\n    end\n    [response, time]","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/rubric_llm_service.rb#L173-L209","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure LLM generation is only invoked from the Assignment rubric editor (assignment must be an AbstractAssignment subclass instance).","Check the association_object class in the controller and return a clear client error before reaching the service.","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."],"exampleFix":"// before\nRubricLlmService.new(rubric).generate_criteria_via_llm(association_object: quiz, ...)\n// after\nunless association_object.is_a?(AbstractAssignment)\n  return render json: { error: 'LLM rubric generation is only available for assignments' }, status: :unprocessable_entity\nend\nRubricLlmService.new(rubric).generate_criteria_via_llm(association_object: association_object, ...)","handlingStrategy":"type-guard","validationCode":"unless association_object.is_a?(AbstractAssignment)\n  return render json: { error: 'AI rubric generation requires an assignment' }, status: :unprocessable_entity\nend","typeGuard":"def assignment_context?(obj)\n  obj.is_a?(AbstractAssignment)\nend","tryCatchPattern":"begin\n  service.generate_criteria_via_llm(...)\nrescue RuntimeError => e\n  raise unless e.message.include?('only available for rubrics associated with an Assignment')\n  render json: { error: 'unsupported association type' }, status: :unprocessable_entity\nend","preventionTips":["Only mount the LLM generation flow inside the assignment rubric editor.","Type-check association_object before constructing RubricLlmService.","Don't wire the generate button on quiz/account rubric pages."],"tags":["rubric","llm","assignment","type-mismatch"],"backgroundTag":"type-mismatch","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}