instructure/canvas-lms · warning · InvalidPrompt

Unsupported prompt

Error message

Unsupported prompt

What it means

StudyAssist::InvalidPrompt raised by StudyAssist#call when the user's prompt matches none of the TOOLS prompt_pattern regexes. StudyAssist routes free-form prompts to a specific tool (flashcards, quizzes, etc.); unrouteable prompts are rejected before any tool runs.

Solutions

  1. Use one of the supported prompt forms matched by the TOOLS prompt_patterns (e.g. 'make flashcards about ...')
  2. Inspect StudyAssist::TOOLS to see the accepted prompt patterns
  3. Update the prompt_pattern regexes to cover new phrasings if the tool should handle them
  4. Handle InvalidPrompt in the controller/API layer and show the user the supported prompts

Example fix

// before
StudyAssist.new(course:, prompt: params[:prompt]).call
// after
begin
  StudyAssist.new(course:, prompt: params[:prompt]).call
rescue StudyAssist::InvalidPrompt
  render json: { error: 'Unsupported prompt', supported: StudyAssist::TOOLS.keys }, status: :bad_request
end
Defensive patterns

Strategy: try-catch

Validate before calling

supported = StudyAssist::TOOLS.any? { |_, cfg| prompt.match?(cfg[:prompt_pattern]) }
raise ArgumentError, 'unsupported prompt' unless supported

Type guard

null

Try / catch

begin
  StudyAssist.new(course:, prompt:).call
rescue StudyAssist::InvalidPrompt
  # return 400 with the list of supported prompts
rescue StudyAssist::ToolDisabled => e
  # return 403 indicating the feature flag is off for this course
end

Prevention

When it happens

Trigger: Calling StudyAssist.new(course:, prompt: "some free text").call where the prompt does not match any tool's prompt_pattern regex, and is not blank (blank prompts build chips instead).

Common situations: Users typing generic questions ('help me study') that no regex matches; localized/non-English prompts; TOOLS patterns narrowed by a recent change; frontend sending raw input instead of a predefined chip prompt.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at app/services/study_assist.rb:100

      return :chips if prompt.blank?

      TOOLS.find { |_, cfg| prompt.match?(cfg[:prompt_pattern]) }&.first || :unknown
    end

    def initialize(course:, user:, prompt:, state:, locale: I18n.locale.to_s, regenerate: false)
      @course = course
      @user = user
      @prompt = prompt.to_s
      @state = state || {}
      @locale = locale
      @regenerate = regenerate || @prompt.match?(REGENERATE_PROMPT_PATTERN)
    end

    def call
      return build_chips if @prompt.blank?

      tool_key, tool_config = TOOLS.find { |_, cfg| @prompt.match?(cfg[:prompt_pattern]) }
      raise InvalidPrompt, "Unsupported prompt" unless tool_key

      unless @course.feature_enabled?(:study_assist) && @course.feature_enabled?(tool_config[:feature_flag])
        raise ToolDisabled, tool_key.to_s
      end

      content = resolve_content

      llm_config = LLMConfigs.config_for(tool_config[:llm_config])
      raise "No LLM config found for #{tool_config[:llm_config]}" if llm_config.nil?

      cache_key = response_cache_key(tool_key, llm_config, content)
      Rails.cache.delete(cache_key) if @regenerate

      Rails.cache.fetch(cache_key, expires_in: RESPONSE_CACHE_TTL) do
        InstLLMHelper.with_rate_limit(user: @user, llm_config:) do
          raw = call_cedar(tool_key, llm_config, content)
          build_response(tool_key, raw)
        end

View on GitHub (pinned to 1c9f0bb801)