instructure/canvas-lms · error · ArgumentError
Options must be a hash
Error message
Options must be a hash
What it means
LlmConfig#validate! raises ArgumentError when options is not a Hash. options holds per-request LLM parameters (temperature, messages, etc.) and must be a hash that generate_prompt_and_options can deep_dup and substitute into.
Solutions
- Pass a Hash (use {} if no options are needed).
- Parse JSON option blobs with JSON.parse before constructing the config.
- Fix the YAML/JSON config so options is a mapping, not a list.
Example fix
// before
LlmConfig.new("gpt4", "gpt-4", nil, template, nil)
// after
LlmConfig.new("gpt4", "gpt-4", nil, template, {temperature: 0.7}) Defensive patterns
Strategy: type-guard
Validate before calling
raise ArgumentError, "options must be Hash" unless options.is_a?(Hash)
Type guard
def valid_options?(v) = v.is_a?(Hash)
Try / catch
begin
cfg = LlmConfig.new(name, model_id, rate_limit, template, options)
rescue ArgumentError => e
Rails.logger.error("Invalid options: #{e.message}")
raise
end Prevention
- Default to {} rather than nil when no options are needed
- JSON.parse any serialized options before constructing LlmConfig
When it happens
Trigger: LlmConfig.new(name, model_id, rate_limit, template, options) where options is nil, an array, or another non-hash value.
Common situations: Omitting the options argument entirely (nil); YAML config where options is a list; passing JSON string instead of a parsed hash.
Related errors
- Model ID must be a string
- Name must be a string
- Template must be a string
- Rate limit must be either nil, or hash with :limit and…
- A course did not pass validation
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/94eca7e0f4e5bb8a.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/llm_config.rb:67
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)