instructure/canvas-lms · warning · RateLimited
Rate limit exceeded
Error message
Rate limit exceeded
What it means
StudyAssist::RateLimited is raised when the underlying Cedar LLM call throws InstLLMHelper::RateLimitExceededError, meaning the LLM provider rejected the request because a rate limit (per user/token/account) was exceeded. The service rescues the low-level error, logs a warning, and re-raises it as a domain-specific RateLimited error preserving the message.
Solutions
- Back off and retry the call after the rate-limit window (honor Retry-After if available)
- Inspect llm_config for the Cedar/InstLLM credentials and request a higher quota/tier
- Add client-side throttling/queueing in front of StudyAssist calls
- Cache or reuse recent LLM responses for identical prompts/content
Example fix
// before result = StudyAssist.new(course:, user:, prompt:).call // after begin result = StudyAssist.new(course:, user:, prompt:).call rescue StudyAssist::RateLimited => e sleep(backoff) retry end
Defensive patterns
Strategy: retry
Validate before calling
null
Type guard
null
Try / catch
begin
StudyAssist.new(course:, user:, prompt:, page_id:).call
rescue StudyAssist::RateLimited => e
Rails.logger.warn("rate limited: #{e.message}")
retry_after_backoff
end Prevention
- Apply exponential backoff with jitter on retries
- Throttle calls client-side per user
- Monitor rate-limit warnings in logs
- Use dedicated higher-quota LLM credentials for production
When it happens
Trigger: Calling StudyAssist#call with a valid prompt, enabled features, and resolvable content, but the Cedar/InstLLM backend returns 429 because the request quota was exhausted (too many requests in the window).
Common situations: Bursty student usage hitting shared LLM API quotas; missing or low rate-limit tier on the configured API key; batch jobs or retries fanning out calls; integration tests hammering the endpoint.
Related errors
- Content exceeds # character limit
- Unsupported prompt
- Cedar rate limit exceeded for #
- File access denied
- File is locked
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/57f30bb6e4997203.
Report an issue: GitHub.
Appendix: source
Thrown at app/services/study_assist.rb:122
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
end
rescue InstLLMHelper::RateLimitExceededError => e
Rails.logger.warn("Study Assist rate limit exceeded for #{tool_key}: #{e.message}")
raise RateLimited, e.message
end
private
def build_chips
chips = TOOLS.each_with_object([]) do |(_, cfg), memo|
memo << { chip: cfg[:chip_label], prompt: cfg[:chip_label] } if @course.feature_enabled?(cfg[:feature_flag])
end
{ chips: }
end
# --- Content resolution ---
def resolve_content
page_id = @state["pageID"] || @state[:pageID]
file_id = @state["fileID"] || @state[:fileID]
content =View on GitHub (pinned to 1c9f0bb801)