{"record":{"id":"02b228bd70fb704a","repo":"we-promise/sure","slug":"not-found-02b228","errorCode":"not_found","errorMessage":"Transaction not found","messagePattern":"Transaction not found","errorType":"http","errorClass":"ActiveRecord::RecordNotFound","httpStatus":404,"severity":"error","filePath":"app/controllers/api/v1/transactions_controller.rb","lineNumber":204,"sourceCode":"\n    render json: {\n      message: \"Transaction deleted successfully\"\n    }, status: :ok\n\n  rescue => e\n    Rails.logger.error \"TransactionsController#destroy error: #{e.message}\"\n    Rails.logger.error e.backtrace.join(\"\\n\")\n\n    render json: {\n      error: \"internal_server_error\",\n      message: \"An unexpected error occurred\"\n    }, status: :internal_server_error\n  end\n\n  private\n\n    def set_transaction\n      raise ActiveRecord::RecordNotFound unless valid_uuid?(params[:id])\n\n      family = current_resource_owner.family\n      @transaction = family.transactions\n        .joins(entry: :account)\n        .merge(Account.accessible_by(current_resource_owner))\n        .find(params[:id])\n      @entry = @transaction.entry\n    rescue ActiveRecord::RecordNotFound\n      render json: {\n        error: \"not_found\",\n        message: \"Transaction not found\"\n      }, status: :not_found\n    end\n\n    def ensure_read_scope\n      authorize_scope!(:read)\n    end\n","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/controllers/api/v1/transactions_controller.rb#L186-L222","documentation":"Api::V1::TransactionsController#set_transaction (app/controllers/api/v1/transactions_controller.rb:197-209) looks up the transaction through family.transactions joined to entry → account merged with Account.accessible_by(owner). It rescues ActiveRecord::RecordNotFound itself and renders 404 { error: 'not_found', message: 'Transaction not found' } — a direct render, not a re-raise. Non-UUID ids, missing rows, and transactions on accounts the owner cannot access all take this path.","triggerScenarios":"GET/PATCH/DELETE /api/v1/transactions/:id with a non-UUID; a deleted transaction; a transaction whose account was revoked from the owner (no longer accessible_by) — for example a formerly shared account.","commonSituations":"Access to a shared account was revoked, so history that used to be fetchable now 404s; bulk importers retrying after transactions were merged/deleted by duplicate detection; stale ids in email-deep-links.","solutions":["List with GET /api/v1/transactions and use a current id","Confirm the account is still accessible to the token owner (not revoked/archived)","Validate UUID format before the call","On bulk operations, tolerate 404s for rows removed by dedupe rather than aborting the batch"],"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, 'transaction id must be a UUID'","typeGuard":null,"tryCatchPattern":"begin\n  client.get(\"/api/v1/transactions/#{id}\")\nrescue Faraday::ResourceNotFound\n  # 404 { error: 'not_found', message: 'Transaction not found' }\nend","preventionTips":["Source ids from GET /api/v1/transactions for the same token","In bulk jobs, skip 404s removed by dedupe instead of failing the run","After account-access revocation, expect history to 404"],"tags":["rails","activerecord","record-not-found","http-404","uuid","permissions"],"backgroundTag":"record-not-found","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}