{"record":{"id":"46dd0d19ab49bdda","repo":"instructure/canvas-lms","slug":"no-question-type-used-when-trying-to-parse-a-qti-question","errorCode":null,"errorMessage":"No question type used when trying to parse a qti question","messagePattern":"No question type used when trying to parse a qti question","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gems/plugins/qti_exporter/lib/qti/assessment_item_converter.rb","lineNumber":69,"sourceCode":"        @href = @package_root.item_path(@manifest_node[\"href\"])\n        if (title = @manifest_node.at_css(\"title langstring\") ||\n           @manifest_node.at_css(\"xmlns|title xmlns|langstring\", \"xmlns\" => Qti::Converter::IMS_MD))\n          @title = title.text\n        end\n      else\n        @qti_data = opts[:qti_data]\n      end\n\n      @question = { answers: [],\n                    correct_comments: \"\",\n                    incorrect_comments: \"\",\n                    question_text: \"\" }\n    end\n\n    # This should be implemented in the children classes to do the type-specific parsing\n    def parse_question_data\n      @log.error \"No question type used...\"\n      raise \"No question type used when trying to parse a qti question\"\n    end\n\n    def create_doc\n      create_xml_doc\n    end\n\n    def create_xml_doc\n      @doc = if @manifest_node\n               Nokogiri::XML(File.open(@href))\n             else\n               Nokogiri::XML(@qti_data)\n             end\n    end\n\n    EXCLUDED_QUESTION_TEXT_CLASSES = [\"RESPONSE_BLOCK\", \"RIGHT_MATCH_BLOCK\"].freeze\n\n    def create_instructure_question\n      begin","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/gems/plugins/qti_exporter/lib/qti/assessment_item_converter.rb#L51-L87","documentation":"assessment_item_converter is an abstract base: parse_question_data is a template method meant to be overridden by type-specific subclasses (multiple_choice, essay, etc.). The base implementation logs and raises because no concrete question-type parser handled the item. It means the QTI item's type could not be classified into a known converter class.","triggerScenarios":"A QTI <assessmentItem> whose question type maps to no known subclass, so the generic AssessmentItemConverter instance itself has parse_question_data called on it during a QTI import.","commonSituations":"Importing QTI packages with exotic or vendor-specific question types; malformed <question_type> metadata; a third-party LMS export using types Canvas doesn't recognize.","solutions":["Inspect the QTI XML to see what question_type was detected for the failing item","Add/extend a subclass in lib/qti/ that supports the missing type, or extend the type-detection mapping","Preprocess/migrate the source package to a supported QTI type (e.g. convert to multiple_choice)","Capture the package and report as an importer bug if the type should be supported"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  converter.parse_question_data\nrescue RuntimeError => e\n  raise unless e.message.start_with?('No question type used')\n  importer.add_warning(:unknown_question_type, item.identifier)\n  UnsupportedQuestionSkip.new(item)\nend","preventionTips":["Normalize vendor QTI packages before import","Map unknown types to a generic fallback converter","Keep a corpus test of QTI samples covering all supported types"],"tags":["ruby","qti","importer","abstract-method"],"backgroundTag":"abstract-method-not-implemented","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"}