{"record":{"id":"ca65f569cf50ab1f","repo":"we-promise/sure","slug":"validation-failed-ca65f5","errorCode":"validation_failed","errorMessage":"rule_id must be a valid UUID","messagePattern":"rule_id must be a valid UUID","errorType":"validation","errorClass":"Api::V1::RuleRunsController::InvalidFilterError","httpStatus":422,"severity":"warning","filePath":"app/controllers/api/v1/rule_runs_controller.rb","lineNumber":53,"sourceCode":"      raise ActiveRecord::RecordNotFound, \"Rule run not found\" unless valid_uuid?(params[:id])\n\n      @rule_run = rule_runs_scope.find(params[:id])\n    end\n\n    def ensure_read_scope\n      authorize_scope!(:read)\n    end\n\n    def rule_runs_scope\n      RuleRun\n        .joins(:rule)\n        .where(rules: { family_id: current_resource_owner.family.id })\n        .includes(:rule)\n    end\n\n    def apply_filters(query)\n      if params[:rule_id].present?\n        raise InvalidFilterError, \"rule_id must be a valid UUID\" unless valid_uuid?(params[:rule_id])\n\n        query = query.where(rule_id: params[:rule_id])\n      end\n\n      if params[:status].present?\n        raise InvalidFilterError, \"status must be one of: #{STATUSES.join(', ')}\" unless STATUSES.include?(params[:status])\n\n        query = query.where(status: params[:status])\n      end\n\n      if params[:execution_type].present?\n        unless EXECUTION_TYPES.include?(params[:execution_type])\n          raise InvalidFilterError, \"execution_type must be one of: #{EXECUTION_TYPES.join(', ')}\"\n        end\n\n        query = query.where(execution_type: params[:execution_type])\n      end\n","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/controllers/api/v1/rule_runs_controller.rb#L35-L71","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nGET /api/v1/rule_runs?rule_id=grocery-rule\n# after\nGET /api/v1/rule_runs?rule_id=0e8d1ceb-5b6d-4a85-9f2e-74f3b1a2c9d4","handlingStrategy":"validation","validationCode":"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\nparams[:rule_id] && !UUID_RE.match?(params[:rule_id]) and raise ArgumentError, 'rule_id must be a valid UUID'","typeGuard":"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)","tryCatchPattern":"begin\n  client.get('/api/v1/rule_runs', { rule_id: rid })\nrescue Faraday::UnprocessableEntity => e\n  # 422 validation_failed — e.response[:body]['message'] names the bad param\nend","preventionTips":["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"],"tags":["rails","query-params","validation","http-422","uuid"],"backgroundTag":"invalid-query-parameter","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}