antiwork/gumroad · error · ActiveRecord::RecordInvalid
This commission's deposit is no longer in a completable stat
Error message
This commission's deposit is no longer in a completable state, so it can no longer be completed.
What it means
Raised as ActiveRecord::RecordInvalid by Commission#ensure_deposit_is_chargeable! (app/models/commission.rb:145) during the completion flow when deposit_is_chargeable? returns false. The check is deliberately strict: the commission must be is_in_progress?, the deposit purchase is re-read from the database (Purchase.find, not the memoized association) and must be in a successful state including test_successful, and it must not be refunded, stripe_partially_refunded, or chargedback_not_reversed. The fresh read exists because refunding the deposit is the documented way for sellers to reject a commission, and nothing transitions the commission when that refund lands through another instance.
Source
Thrown at app/models/commission.rb:149
def once_per_cart_discounted_display_price_cents
discount = deposit_purchase.purchase_offer_code_discount
return unless discount&.once_per_cart? && !discount.offer_code_is_percent
return if discount.pre_discount_displayed_price_cents.blank?
total = [discount.pre_discount_displayed_price_cents - discount.offer_code_amount, 0].max
minimum = deposit_purchase.link.currency["min_price"]
total = minimum if total.positive? && total < minimum
total
end
# Refunding the deposit is how the Help Center tells sellers to reject a commission, and
# nothing transitions the commission when they do — so the deposit is re-read at charge time.
def ensure_deposit_is_chargeable!
return if deposit_is_chargeable?
errors.add(:base, "This commission's deposit is no longer in a completable state, so it can no longer be completed.")
raise ActiveRecord::RecordInvalid, self
end
def ensure_deliverable_is_attached!
return if files.attached?
errors.add(:base, "Attach at least one file before completing this commission.")
raise ActiveRecord::RecordInvalid, self
end
def deposit_is_chargeable?
return false unless is_in_progress?
# A fresh read, not the memoized association — a refund can land through another instance
# after this commission was loaded. `find` rather than `reload` because the completion
# purchase prices variants from the memoized deposit's loaded association objects.
deposit = Purchase.find(deposit_purchase_id)
# Including test: a seller buying their own commission product gets a `test_successful`
# deposit, and completing it is a supported flow that skips charging entirely.View on GitHub (pinned to afeacbd394)
Solutions
- Before completing, re-check the same conditions the guard does: commission.is_in_progress? and the freshly-read deposit purchase's state (successful-including-test, not refunded/partially-refunded/charged-back).
- If the deposit was refunded intentionally, treat the commission as rejected — do not attempt completion; no state transition exists for refunds by design.
- Refresh the commission state in the UI before showing the Complete action so stale sessions don't attempt completion against a changed deposit.
- Handle ActiveRecord::RecordInvalid at the completion endpoint and return the model's errors.full_messages as a 422.
Example fix
# before
commission.complete! # RecordInvalid: deposit no longer completable
# after
def complete_if_chargeable!(commission)
deposit = Purchase.find(commission.deposit_purchase_id)
chargeable = commission.is_in_progress? &&
Purchase::ALL_SUCCESS_STATES_INCLUDING_TEST.include?(deposit.purchase_state) &&
!deposit.refunded? && !deposit.stripe_partially_refunded? && !deposit.chargedback_not_reversed?
return { rejected: true } unless chargeable
commission.complete!
end Defensive patterns
Strategy: validation
Validate before calling
deposit = Purchase.find(commission.deposit_purchase_id) chargeable = commission.is_in_progress? && Purchase::ALL_SUCCESS_STATES_INCLUDING_TEST.include?(deposit.purchase_state) && !deposit.refunded? && !deposit.stripe_partially_refunded? && !deposit.chargedback_not_reversed? return reject_path unless chargeable
Try / catch
begin
commission.complete!
rescue ActiveRecord::RecordInvalid
render json: { errors: commission.errors.full_messages }, status: :unprocessable_entity
end Prevention
- Treat a refunded deposit as commission rejection — no completion attempt.
- Re-check deposit state at click time, not page-load time; refunds land through other instances.
- Remember test_successful deposits are completable; only non-success/refunded/charged-back states are not.
When it happens
Trigger: Calling the commission-complete endpoint when: the commission already left in_progress; the deposit Purchase.purchase_state is not in Purchase::ALL_SUCCESS_STATES_INCLUDING_TEST (failed/errored); or the deposit was refunded, partially refunded on Stripe, or charged back without reversal. Also hit when a refund lands between page load and clicking Complete — the guard re-reads the deposit at charge time and catches it.
Common situations: Seller refunds the deposit to reject the commission, then (or a colleague in another session) tries to complete it anyway. Stale UI still showing a Complete button after the buyer charged back the deposit. Completion racing an in-flight refund.
Related errors
- This commission has already been completed, so its files can
- Attach at least one file before completing this commission.
- ${response.message}
- Server returned error response.
- Request failed (${response.status})
AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21).
Data as JSON: /api/errors/129f246f120a70d0.
Report an issue: GitHub.