instructure/canvas-lms · error · ArgumentError
Rate limit must be either nil, or hash with :limit and…
Error message
Rate limit must be either nil, or hash with :limit and :period keys
What it means
LlmConfig#validate! raises ArgumentError unless rate_limit is nil or exactly a Hash with keys [:limit, :period] (in that order per keys == %i[limit period]). Any other shape — extra keys, missing keys, wrong types, or a different key order — is rejected.
Solutions
- Pass exactly {limit: <int>, period: <symbol>} or nil.
- If loading from YAML, symbolize keys and reorder/normalize to [:limit, :period].
- Remove unsupported keys from the rate_limit hash.
Example fix
// before
LlmConfig.new("gpt4", "gpt-4", {"limit" => 10, "period" => :minute}, template, {})
// after
LlmConfig.new("gpt4", "gpt-4", {limit: 10, period: :minute}, template, {}) Defensive patterns
Strategy: validation
Validate before calling
ok = rate_limit.nil? || (rate_limit.is_a?(Hash) && rate_limit.keys == %i[limit period]) raise ArgumentError, "bad rate_limit shape" unless ok
Type guard
def valid_rate_limit?(rl) = rl.nil? || (rl.is_a?(Hash) && rl.keys == %i[limit period])
Try / catch
begin
cfg = LlmConfig.new(name, model_id, rate_limit, ...)
rescue ArgumentError => e
Rails.logger.error("Invalid rate_limit: #{e.message}")
raise
end Prevention
- Build rate limits via a factory that always emits {limit:, period:} in that order
- Symbolize and normalize hashes loaded from YAML before passing them in
- Avoid adding ad-hoc keys to the rate_limit hash
When it happens
Trigger: LlmConfig.new(name, model_id, rate_limit, ...) where rate_limit is a string, a hash with keys like {limit: n} only, keys in a different order, or containing extra keys.
Common situations: Config parsed from YAML where keys load as strings ('limit' vs :limit); adding new rate-limit fields the validator doesn't know; constructing the hash in a different key order.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Model ID must be a string
- Name must be a string
- Options must be a hash
- Template must be a string
- A course did not pass validation
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/83d240111c1f0cab.
Report an issue: GitHub.
Appendix: source
Thrown at app/models/llm_config.rb:65
new_options[key] = value.gsub("<#{placeholder_prefix}_PLACEHOLDER>", sub_value.to_s) if value.is_a?(String)
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)