{"record":{"id":"8085d5cc83643283","repo":"we-promise/sure","slug":"record-not-found-8085d5","errorCode":"record_not_found","errorMessage":"Security not found","messagePattern":"Security not found","errorType":"http","errorClass":"ActiveRecord::RecordNotFound","httpStatus":404,"severity":"error","filePath":"app/controllers/api/v1/securities_controller.rb","lineNumber":32,"sourceCode":"    @pagy, @securities = pagy(\n      securities_query,\n      page: safe_page_param,\n      limit: @per_page\n    )\n\n    render :index\n  rescue Api::V1::SecurityResourceFiltering::InvalidFilterError => e\n    render_validation_error(e.message)\n  end\n\n  def show\n    render :show\n  end\n\n  private\n\n    def set_security\n      raise ActiveRecord::RecordNotFound, \"Security not found\" unless valid_uuid?(params[:id])\n\n      @security = securities_scope.find(params[:id])\n    end\n\n    def ensure_read_scope\n      authorize_scope!(:read)\n    end\n\n    def securities_scope\n      Security\n        .where(id: scoped_security_ids)\n    end\n\n    def apply_filters(query)\n      query = query.where(\"LOWER(securities.ticker) = ?\", params[:ticker].to_s.strip.downcase) if params[:ticker].present?\n      query = query.where(exchange_operating_mic: params[:exchange_operating_mic].to_s.strip.upcase) if params[:exchange_operating_mic].present?\n      if params[:kind].present?\n        invalid_filter!(\"kind must be one of: #{Security::KINDS.join(', ')}\") unless Security::KINDS.include?(params[:kind])","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/controllers/api/v1/securities_controller.rb#L14-L50","documentation":"Raised by set_security in Api::V1::SecuritiesController (app/controllers/api/v1/securities_controller.rb:32). The valid_uuid? guard rejects malformed ids with the custom 'Security not found' RecordNotFound; otherwise securities_scope — Security.where(id: scoped_security_ids) from SecurityResourceFiltering, i.e. securities tied to the family's accounts/holdings — must contain the row. Result is 404 record_not_found.","triggerScenarios":"GET /api/v1/securities/:id with a non-UUID; a valid UUID for a security the family never held (global security catalog id); a security whose last holding was removed so it dropped out of the scoped set.","commonSituations":"Harvesting security ids from an external reference/API instead of GET /api/v1/securities; selling all positions and having the security vanish from the family scope; id from a demo seed set.","solutions":["List with GET /api/v1/securities and use an id from that response","If the security is missing, create/hold it via the app first so it enters the family scope","Validate UUID format before the call","Handle 404 gracefully — scoped access, not a global catalog"],"exampleFix":null,"handlingStrategy":"try-catch","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\nUUID_RE.match?(id) or raise ArgumentError, 'security id must be a UUID'","typeGuard":null,"tryCatchPattern":"begin\n  client.get(\"/api/v1/securities/#{id}\")\nrescue Faraday::ResourceNotFound\n  # 404 'Security not found': malformed id or security outside family scope\nend","preventionTips":["Treat /securities as family-scoped, not a global catalog","Source ids from GET /api/v1/securities","Re-check scope after positions are fully sold"],"tags":["rails","activerecord","record-not-found","http-404","uuid","securities"],"backgroundTag":"record-not-found","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}