hpyhacking/peatio · error · APIv2::DepositByTxidNotFoundError
2012
2012
Error message
Deposit##txid=#{txid} doesn't exist. What it means
Error code 2012 (DepositByTxidNotFoundError) is raised by GET /api/v2/deposit when current_user.deposits.find_by(txid: params[:txid]) returns nil. The finder is scoped through the authenticated member, so the deposit must both exist in the deposits table AND belong to the access key's account; a txid owned by another user (or recorded by another exchange) produces the same error as a nonexistent one.
Source
Thrown at app/api/api_v2/deposits.rb:31
optional :limit, type: Integer, range: 1..100, default: 3, desc: "Set result limit."
optional :state, type: String, values: Deposit::STATES.map(&:to_s)
end
get "/deposits" do
deposits = current_user.deposits.limit(params[:limit]).recent
deposits = deposits.with_currency(params[:currency]) if params[:currency]
deposits = deposits.with_aasm_state(params[:state]) if params[:state].present?
present deposits, with: APIv2::Entities::Deposit
end
desc 'Get details of specific deposit.'
params do
use :auth
requires :txid
end
get "/deposit" do
deposit = current_user.deposits.find_by(txid: params[:txid])
raise DepositByTxidNotFoundError, params[:txid] unless deposit
present deposit, with: APIv2::Entities::Deposit
end
desc 'Where to deposit. The address field could be empty when a new address is generating (e.g. for bitcoin), you should try again later in that case.'
params do
use :auth
requires :currency, type: String, values: Currency.all.map(&:code), desc: "The account to which you want to deposit. Available values: #{Currency.all.map(&:code).join(', ')}"
end
get "/deposit_address" do
current_user.ac(params[:currency]).payment_address.to_json
end
end
end
View on GitHub (pinned to dab8641137)
Solutions
- List the authenticated account's own deposits via GET /api/v2/deposits and copy the exact txid value the API returns
- If the deposit is brand new, wait for collection/confirmations and retry the lookup
- Confirm the deposit address actually belongs to this account (GET /api/v2/deposit_addresses) — if not, you are querying the wrong member's data
Example fix
# before — txid taken from an external explorer/another exchange
get '/api/v2/deposit', params: auth_params.merge(txid: explorer_txid)
# after — resolve txid from this account's own deposit history first
deposits = get '/api/v2/deposits', params: auth_params
txid = deposits.find { |d| d['currency'] == 'btc' }&.dig('txid')
raise 'no deposit recorded yet' unless txid
get '/api/v2/deposit', params: auth_params.merge(txid: txid) Defensive patterns
Strategy: validation
Validate before calling
# Resolve the txid from this account's own history before the single lookup
deposits = get '/api/v2/deposits', params: auth_params.merge(currency: 'btc')
owned = deposits.any? { |d| d['txid'] == params[:txid] }
return unless owned # skip the call; it would raise 2012
get '/api/v2/deposit', params: auth_params.merge(txid: params[:txid]) Type guard
# Ruby: the txid is valid for this account only if membership resolves
owned_txids = Set.new(deposits.map { |d| d['txid'] })
owned_txids.include?(candidate_txid) Try / catch
Treat 2012 as a terminal lookup miss for this account: report 'not found for this account' rather than retrying — a foreign or unpersisted txid will never appear under the authenticated member.
Prevention
- Source txids from the account's own /deposits listing, never from explorers or other exchanges' withdrawal pages
- For tag/memo chains, store the receiving side's recorded txid, which can differ from the sending exchange's hash
- When polling fresh deposits, back off until collection finishes instead of hammering /deposit
When it happens
Trigger: Querying a txid that belongs to a different account or a different exchange; a typo'd or truncated txid; chain-specific formatting differences (case sensitivity, tag/memo-based chains recording an internal txid that differs from the on-chain hash); a deposit already broadcast but not yet collected and persisted by the deposit worker.
Common situations: Ops scripts copying a txid from an explorer or another exchange's withdrawal page while querying this account's API; support tooling checking the wrong member; polling seconds after broadcasting before confirmations/collection complete.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
AI-assisted analysis of hpyhacking/peatio@dab8641137 (2026-08-23).
Data as JSON: /api/errors/45054fd7b81db6f9.
Report an issue: GitHub.