instructure/canvas-lms · error · ArgumentError

Template must be a string

Error message

Template must be a string

What it means

LlmConfig#validate! raises ArgumentError when the template passed to the initializer is not a String. The prompt template is required to be a string containing the placeholder tokens that generate_prompt_and_options will substitute.

Solutions

  1. Pass the fully rendered template String.
  2. Join prompt parts with .join("\n") before constructing the config.
  3. Fix the config source so the template field is present and a string.

Example fix

// before
LlmConfig.new("gpt4", "gpt-4", nil, ["Hello", "<NAME_PLACEHOLDER>"], {})
// after
LlmConfig.new("gpt4", "gpt-4", nil, "Hello <NAME_PLACEHOLDER>", {})
Defensive patterns

Strategy: type-guard

Validate before calling

raise ArgumentError, "template must be String" unless template.is_a?(String)

Type guard

def valid_template?(v) = v.is_a?(String)

Try / catch

begin
  cfg = LlmConfig.new(name, model_id, rate_limit, template, options)
rescue ArgumentError => e
  Rails.logger.error("Invalid template: #{e.message}")
  raise
end

Prevention

When it happens

Trigger: LlmConfig.new(name, model_id, rate_limit, template, ...) where template is nil, an array of prompt parts, a proc, or any non-string value.

Common situations: Building templates by joining arrays and forgetting to join; nil template from a missing config field; passing a lazily rendered block instead of a rendered string.

Related errors


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

Appendix: source

Thrown at app/models/llm_config.rb:66

      end
    end

    new_options.each_value do |value|
      if value.is_a?(String) && (remaining_placeholder = value.match(/<\w+_PLACEHOLDER>/))
        raise ArgumentError, "Options still contain placeholder: #{remaining_placeholder[0]}"
      end
    end

    [new_template, new_options]
  end

  private

  def validate!
    raise ArgumentError, "Name must be a string" unless @name.is_a?(String)
    raise ArgumentError, "Model ID must be a string" unless @model_id.is_a?(String)
    raise ArgumentError, "Rate limit must be either nil, or hash with :limit and :period keys" unless @rate_limit.nil? || (@rate_limit.is_a?(Hash) && @rate_limit.keys == %i[limit period])
    raise ArgumentError, "Template must be a string" unless @template.is_a?(String)
    raise ArgumentError, "Options must be a hash" unless @options.is_a?(Hash)
  end
end

View on GitHub (pinned to 1c9f0bb801)