{"record":{"id":"f2281f2f0e2ebf57","repo":"instructure/canvas-lms","slug":"quiz-item-malformed","errorCode":null,"errorMessage":"Quiz item malformed","messagePattern":"Quiz item malformed","errorType":"exception","errorClass":"CedarUnavailable","httpStatus":null,"severity":"error","filePath":"app/services/study_assist.rb","lineNumber":296,"sourceCode":"      end\n    end\n\n    def build_summarize_response(raw)\n      text = raw.to_s.strip\n      raise CedarUnavailable, \"Summary response missing\" if text.blank?\n\n      { response: text }\n    end\n\n    def build_quiz_response(raw)\n      items = parse_json_array!(raw)\n      raise CedarUnavailable, \"Quiz response missing items\" if items.blank? || !items.is_a?(Array)\n\n      quiz_items = items.first(10).map do |item|\n        question = item[:question] || item[\"question\"]\n        options = item[:options] || item[\"options\"]\n        result = item[:result] || item[\"result\"]\n        raise CedarUnavailable, \"Quiz item malformed\" if question.blank? || options.blank? || result.nil?\n\n        { question:, answers: options, correctAnswerIndex: result.to_i }\n      end\n\n      { quizItems: quiz_items }\n    end\n\n    def build_flashcards_response(raw)\n      cards = parse_json_array!(raw)\n      raise CedarUnavailable, \"Flashcards response missing items\" if cards.blank? || !cards.is_a?(Array)\n\n      flash_cards = cards.first(10).map do |card|\n        question = card[:question] || card[\"question\"]\n        answer = card[:answer] || card[\"answer\"]\n        raise CedarUnavailable, \"Flashcard item malformed\" if question.blank? || answer.blank?\n\n        { question:, answer: }\n      end","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/services/study_assist.rb#L278-L314","documentation":"Within build_quiz_response, each of the (up to 10) parsed quiz items must have non-blank question, non-blank options, and a non-nil result. Any item missing a field raises CedarUnavailable 'Quiz item malformed'.","triggerScenarios":"build_response -> build_quiz_response when any item in the Cedar JSON array lacks :question/:\"question\", :options/:\"options\", or :result/:\"result\", or has blank question/options / nil result.","commonSituations":"The LLM emits a mix of valid and malformed items (skipped options, missing answer key); prompt drift after a model upgrade changes the item schema; symbol-vs-string keys handled but values still missing.","solutions":["Retry — malformed items are typical stochastic LLM output and often fixed on regeneration.","Log the offending item to see which field is missing; adjust the quiz prompt to demand exact keys question/options/result.","If regeneration is too costly, drop malformed items client-side only when a minimum viable count survives.","Pin/verify the Cedar model version if the schema suddenly changed."],"exampleFix":"// before\n# hard failure on first malformed item\nitems.map { |i| build_item!(i) }\n\n// after\nvalid = items.filter_map { |i| build_item!(i) rescue nil }\nraise StudyAssist::CedarUnavailable, 'Quiz response missing items' if valid.empty?","handlingStrategy":"validation","validationCode":"QUIZ_ITEM_SCHEMA = ->(i) {\n  q = i[:question] || i['question']\n  o = i[:options] || i['options']\n  r = i[:result] || i['result']\n  q.present? && o.present? && !r.nil?\n}\npre_ok = parsed_items.all?(&QUIZ_ITEM_SCHEMA)","typeGuard":"def valid_quiz_item?(item)\n  q = item[:question] || item['question']\n  o = item[:options] || item['options']\n  r = item[:result] || item['result']\n  q.is_a?(String) && q.present? && o.is_a?(Array) && o.any? && !r.nil?\nend","tryCatchPattern":"begin\n  quiz = service.call(tool: :quiz)\nrescue StudyAssist::CedarUnavailable\n  Rails.logger.warn('quiz items malformed; regenerating')\n  quiz = service.call(tool: :quiz)\nend","preventionTips":["Validate each parsed item's question/options/result shape before rendering","Pin the Cedar model version to avoid silent schema drift","Prompt for exact keys question/options/result with example output"],"tags":["llm","quiz","schema","validation"],"backgroundTag":"schema-validation-failed","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"}