{"record":{"id":"619fdad0658236bb","repo":"instructure/canvas-lms","slug":"unsupported-embedding-version-version","errorCode":null,"errorMessage":"Unsupported embedding version #{version}","messagePattern":"Unsupported embedding version #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/smart_search.rb","lineNumber":80,"sourceCode":"      @search_info.map do |_, proc, _|\n        proc.call(course)\n      end\n    end\n\n    def search_scopes(course, user)\n      @search_info.map do |klass, _, proc|\n        [klass, proc.call(course, user)]\n      end\n    end\n\n    def generate_embedding(input, query: false, version: EMBEDDING_VERSION)\n      case version\n      when 1\n        generate_embedding_v1(input)\n      when 2\n        generate_embedding_v2(input, query)\n      else\n        raise ArgumentError, \"Unsupported embedding version #{version}\"\n      end\n    end\n\n    def generate_embedding_v1(input)\n      # NOTE: openai does not differentiate between query and document embeddings\n      url = \"https://api.openai.com/v1/embeddings\"\n      headers = {\n        \"Authorization\" => \"Bearer #{api_key}\",\n        \"Content-Type\" => \"application/json\"\n      }\n\n      data = {\n        input:,\n        model: \"text-embedding-ada-002\"\n      }\n\n      response = JSON.parse(Net::HTTP.post(URI(url), data.to_json, headers).body)\n      raise response[\"error\"][\"message\"] if response[\"error\"]","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/lib/smart_search.rb#L62-L98","documentation":"SmartSearch.generate_embedding dispatches on an explicit embedding version (EMBEDDING_VERSION is 2: v1 = OpenAI ada-002 HTTP API, v2 = Bedrock cohere.embed-multilingual-v3). Passing any version other than 1 or 2 raises ArgumentError 'Unsupported embedding version'.","triggerScenarios":"Calling SmartSearch.generate_embedding(input, version: 3) (or 0, nil, '2' as a string) — e.g. code hardcoding an old/new version instead of using the EMBEDDING_VERSION constant, or persisted records storing a version value that is no longer supported.","commonSituations":"Upgrading/downgrading Canvas where stored embedding versions no longer match supported ones; copy-pasted code passing literal versions; type confusion passing a string '2' instead of integer 2; testing experimental embedding models by bumping version without implementing the branch.","solutions":["Use SmartSearch::EMBEDDING_VERSION instead of hardcoding a version literal","Pass version: 1 or version: 2 explicitly (integers, not strings)","If data was embedded with an older/newer version, re-index with the currently supported version","Check for string/integer type confusion in the version parameter"],"exampleFix":"# before\nembedding = SmartSearch.generate_embedding(text, version: 3)\n# after\nembedding = SmartSearch.generate_embedding(text, version: SmartSearch::EMBEDDING_VERSION)","handlingStrategy":"type-guard","validationCode":"raise ArgumentError, 'version must be 1 or 2' unless [1, 2].include?(version)","typeGuard":"def valid_embedding_version?(v)\n  [1, 2].include?(v)\nend","tryCatchPattern":"begin\n  embedding = SmartSearch.generate_embedding(input, version: version)\nrescue ArgumentError => e\n  Rails.logger.error(\"#{e.message}; falling back to EMBEDDING_VERSION\")\n  embedding = SmartSearch.generate_embedding(input)\nend","preventionTips":["Reference SmartSearch::EMBEDDING_VERSION, never hardcoded numbers","Pass integers, not strings, for version","Re-index stored embeddings when the supported version changes","Test version dispatch when bumping EMBEDDING_VERSION"],"tags":["ruby","smart-search","embeddings","invalid-version"],"backgroundTag":"invalid-enum-value","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"}