{"record":{"id":"171609eceddd494f","repo":"antiwork/gumroad","slug":"invalid-offer-code-171609","errorCode":null,"errorMessage":"Invalid offer code","messagePattern":"Invalid offer code","errorType":"exception","errorClass":"Link::LinkInvalid","httpStatus":422,"severity":"error","filePath":"app/controllers/links_controller.rb","lineNumber":1937,"sourceCode":"\n      if product_permitted_params[:installment_plan].present?\n        @product.create_installment_plan!(product_permitted_params[:installment_plan])\n      end\n    end\n\n    def update_default_offer_code\n      default_offer_code_id = product_permitted_params[:default_offer_code_id]\n\n      return @product.default_offer_code = nil if default_offer_code_id.blank?\n\n      offer_code = @product.user.offer_codes.alive.find_by_external_id!(default_offer_code_id)\n\n      raise Link::LinkInvalid, \"Offer code cannot be expired\" if offer_code.inactive?\n      raise Link::LinkInvalid, \"Offer code must apply to this product\" unless offer_code.applicable?(@product)\n\n      @product.default_offer_code = offer_code\n    rescue ActiveRecord::RecordNotFound\n      raise Link::LinkInvalid, \"Invalid offer code\"\n    end\n\n    def toggle_community_chat!(enabled)\n      return if [Link::NATIVE_TYPE_COFFEE, Link::NATIVE_TYPE_BUNDLE].include?(@product.native_type)\n\n      @product.toggle_community_chat!(enabled)\n    end\n\n    def generate_product_details_using_ai\n      if Rails.env.test?\n        generate_product_cover_and_thumbnail_using_ai\n        generate_product_content_using_ai\n      else\n        cover_thread = Thread.new { generate_product_cover_and_thumbnail_using_ai }\n        content_thread = Thread.new { generate_product_content_using_ai }\n\n        cover_thread.join\n        content_thread.join","sourceCodeStart":1919,"sourceCodeEnd":1955,"githubUrl":"https://github.com/antiwork/gumroad/blob/afeacbd394069a1cbf0c6c50ee8e900925050370/app/controllers/links_controller.rb#L1919-L1955","documentation":"links_controller.rb:1937 converts `ActiveRecord::RecordNotFound` from `@product.user.offer_codes.alive.find_by_external_id!` into `Link::LinkInvalid(\"Invalid offer code\")`. The submitted external id matches no alive offer code owned by the product's seller — deleted code, wrong account, wrong environment, or malformed id. The form save aborts with this message.","triggerScenarios":"Product form submits `default_offer_code_id` for a code deleted in another tab/session; id from a different seller account; id truncated or altered in transit; code exists but is outside the `alive` scope.","commonSituations":"Stale dropdown/hidden field referencing a deleted code; scripts moving ids between environments; concurrent admin sessions deleting codes mid-edit.","solutions":["Reload the product editor so the offer-code list reflects current codes, then re-select.","Verify the id belongs to the same seller account and environment.","Recreate the deleted code if it was removed by mistake and use its new external id.","Submit a blank `default_offer_code_id` to clear the assignment instead of sending a dead id."],"exampleFix":"# before\nput product_path(@product), params: { product: { default_offer_code_id: deleted_code.external_id } }\n\n# after — guard on resolution before the request\ncode = @product.user.offer_codes.alive.exists?(external_id: submitted_id) ? submitted_id : nil\nput product_path(@product), params: { product: { default_offer_code_id: code } }","handlingStrategy":"validation","validationCode":"code = @product.user.offer_codes.alive.find_by(external_id: submitted_id)\nraise Link::LinkInvalid, \"Invalid offer code\" unless code","typeGuard":"def resolvable_offer_code?(user, external_id)\n  user.offer_codes.alive.exists?(external_id: external_id)\nend","tryCatchPattern":"begin\n  offer_code = @product.user.offer_codes.alive.find_by_external_id!(id)\nrescue ActiveRecord::RecordNotFound\n  # refresh picker; never blind-retry the same external id\nend","preventionTips":["Rebuild the offer-code picker on each form load; no cached dropdowns.","Delete-then-default operations should clear defaults atomically.","Validate ids against the same seller account and environment before submitting.","Log the submitted id server-side (it is non-sensitive) to diagnose environment skew."],"tags":["offer-codes","product-settings","record-not-found","link-invalid","validation"],"backgroundTag":"offer-code-not-found","analyzedSha":"afeacbd394069a1cbf0c6c50ee8e900925050370","analyzedAt":"2026-08-21T17:58:52.159Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}