we-promise/sure · warning · Api::V1::RuleRunsController::InvalidFilterError
validation_failed
validation_failed
Error message
rule_id must be a valid UUID
What it means
Api::V1::RuleRunsController#apply_filters (app/controllers/api/v1/rule_runs_controller.rb:52-55) validates the rule_id query param with valid_uuid? before using it in a where clause. A present but malformed rule_id raises the controller-local InvalidFilterError, which index rescues and renders as 422 validation_failed with message 'rule_id must be a valid UUID'. Only the format is checked, not existence.
Source
Thrown at app/controllers/api/v1/rule_runs_controller.rb:53
raise ActiveRecord::RecordNotFound, "Rule run not found" unless valid_uuid?(params[:id])
@rule_run = rule_runs_scope.find(params[:id])
end
def ensure_read_scope
authorize_scope!(:read)
end
def rule_runs_scope
RuleRun
.joins(:rule)
.where(rules: { family_id: current_resource_owner.family.id })
.includes(:rule)
end
def apply_filters(query)
if params[:rule_id].present?
raise InvalidFilterError, "rule_id must be a valid UUID" unless valid_uuid?(params[:rule_id])
query = query.where(rule_id: params[:rule_id])
end
if params[:status].present?
raise InvalidFilterError, "status must be one of: #{STATUSES.join(', ')}" unless STATUSES.include?(params[:status])
query = query.where(status: params[:status])
end
if params[:execution_type].present?
unless EXECUTION_TYPES.include?(params[:execution_type])
raise InvalidFilterError, "execution_type must be one of: #{EXECUTION_TYPES.join(', ')}"
end
query = query.where(execution_type: params[:execution_type])
end
View on GitHub (pinned to e69894adb9)
Solutions
- Send rule_id as a canonical UUID, e.g. ?rule_id=0e8d1ceb-5b6d-4a85-9f2e-74f3b1a2c9d4
- Take rule ids from GET /api/v1/rules, not from logs or UI labels
- Validate UUID format client-side before the request
- Remember an empty result set means 'no runs for that rule', not an error
Example fix
# before GET /api/v1/rule_runs?rule_id=grocery-rule # after GET /api/v1/rule_runs?rule_id=0e8d1ceb-5b6d-4a85-9f2e-74f3b1a2c9d4
Defensive patterns
Strategy: validation
Validate before calling
UUID_RE = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i
params[:rule_id] && !UUID_RE.match?(params[:rule_id]) and raise ArgumentError, 'rule_id must be a valid UUID' Type guard
def valid_uuid?(v) = v.to_s.match?(/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i) Try / catch
begin
client.get('/api/v1/rule_runs', { rule_id: rid })
rescue Faraday::UnprocessableEntity => e
# 422 validation_failed — e.response[:body]['message'] names the bad param
end Prevention
- Take rule ids from GET /api/v1/rules, never from labels/logs
- Run a UUID regex check on every id-typed filter
- Remember: valid-but-unknown rule_id returns [], not an error
When it happens
Trigger: GET /api/v1/rule_runs?rule_id=abc, ?rule_id=12345, or any 8-4-4-4-12-violating string. A well-formed but non-existent rule_id does NOT error — it just returns an empty list.
Common situations: Passing a rule name, numeric id, or partially copied UUID; sending the rule's slug instead of its id; whitespace or encoding damage in the query string.
Related errors
- validation_failed
- validation_failed
- #{key} must be an ISO 8601 date
- #{key} must be an ISO 8601 date
- validation_error
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/ca65f569cf50ab1f.
Report an issue: GitHub.