Troubleshooting
The failure messages this integration actually produces — what each one means, which layer it comes from, and the fix that works rather than the one that looks obvious.
Most problems here are one of four things: the licence file, the credentials, the IP allowlist, or a rate-limit ban. The symptoms overlap, so work from the message rather than the symptom.
Start every investigation at Admin → Finance → Exchange Providers and press Verify Credentials. It builds a throwaway connection, loads markets and fetches your balance, and its message names the layer that failed.
Connection and credentials
"No active exchange provider" on the exchange screen
No row in the exchange table has status = true. Either you never enabled
Binance, or enabling a different provider switched it off — only one provider
can be active, and enabling one disables the rest in the same transaction.
Fix it from Admin → System → Extensions → Exchanges
(/admin/system/extension?type=exchange).
"Cannot enable exchange provider: License not activated"
The enable call returned 403 because lic/38650585.lic does not exist under the
project root. The check reads the disk, not the database, so a licence column
that says "Licensed" does not help.
This is the usual symptom after restoring a database into a fresh checkout, or
after a deployment that did not carry the lic folder across. Re-activate from
Admin → System → Extensions, or from
/admin/system/license?productId=38650585.
"API credentials are missing from environment variables"
APP_BINANCE_API_KEY or APP_BINANCE_API_SECRET is absent or empty in the
environment the backend process started with. Three things produce this that
look like something else:
- The variables were added to
.envbut the process was never restarted. They are read at boot. - They were added to the wrong
.env— they belong in the project root file. - A typo in the name. The names are built at runtime from the provider alias, so a misspelling is indistinguishable from an absent variable.
After three failures the manager stops trying for thirty minutes. If you fixed it and nothing changed, restart the backend rather than waiting.
"Invalid API credentials. Please check your API key and secret."
Binance rejected the signature. The key and secret are present but wrong — most often a truncated secret, or a secret from a key that has since been deleted.
Note that a key which is fine but whose IP allowlist does not include your server fails here too, because the rejection happens at the same layer. Prove the IP before you regenerate the key: see Creating the Binance API key.
"Your server's location is blocked by this exchange"
HTTP 451. Binance refuses connections from your server's region. No credential change will help.
Configure an outbound proxy in the Settings tab of the exchange provider screen, test it before saving, and then add the proxy's IP to the key's allowlist — the proxy is the address Binance sees.
"Server time synchronization failed"
The platform signs requests from just behind Binance's clock and re-measures the offset every five minutes. It also retries the whole connection with a fresh sync when Binance reports a timestamp error. Seeing this after those retries means the server clock is drifting faster than the measurement can absorb.
Fix the host clock — install and enable NTP — rather than adjusting anything in the platform.
Everything looks fine but currency import returns nothing
This is the silent fallback. When the authenticated market load fails for a reason that is not a rate limit and not a clock problem, the platform builds a second, credential-less connection so public data keeps flowing.
Charts and tickers carry on working. Currency import, deposit addresses and the balance screen do not, because all three need a signed request. Check the backend log for the warning naming the fallback, then fix the underlying credential or network problem and restart.
Markets and data
The market list is empty
Markets are created switched off by the import. Enable the pairs you want on
/admin/finance/exchange/market. If the table itself is empty, the import has
not been run — see Currencies, markets and charts.
A market I enabled has switched itself off
When the ticker stream receives an error from Binance that names specific symbols, the platform disables exactly those markets and continues rather than letting one bad row break the whole batch.
The reason is only in the backend log. Common causes: the pair was delisted, or it is not a spot market on Binance any more.
Tickers stop updating for everyone at once
Check for a rate-limit ban before anything else. While exchange:ban_status is
set in Redis, every path that needs Binance returns nothing and logs a warning —
the site stays up and simply stops moving.
The chart settings screen reports the ban state and the remaining seconds. See Connection, rate limits and bans.
The currency import offers to delete everything
The catalogue came back empty, which on Binance means the connection is not authenticated — the currency endpoint is signed. The import is preview-first precisely so you see the delete count before agreeing to it.
Do not confirm. Verify credentials, fix them, restart, and re-run the preview.
Import says markets are "kept for open orders"
Markets Binance has delisted are removed, except any that still carry open orders — deleting those would strand the balances those orders are holding. Cancel or settle them, then import again.
Order history on removed markets is never deleted, whatever the preview says about market counts.
Orders
"Exchange service is currently unavailable" when a customer places an order
The order route could not obtain a connection. Either no provider is enabled, or a rate-limit ban is active, or the connection is inside its thirty-minute failure cooldown.
"Unable to process order" with the venue name replaced by asterisks
That is deliberate. Provider names are scrubbed from customer-facing error text so your customers do not learn which exchange backs the platform from an error message. The full message is in the backend log.
Orders are rejected for price, amount or cost
Those limits come from the market's imported metadata, not from Binance in real time. If Binance changed a pair's minimum notional, your copy is stale until you re-import markets.
Deposits
A customer deposited and nothing happened
The transaction hash is the only link between an incoming transfer and a customer — every customer sees the same Binance address for a given currency and network. If the customer never submitted a hash, or submitted the wrong one, there is no ledger entry to complete.
Reconcile manually against Binance's deposit history. Nothing in the platform will prompt you.
"Transaction not found" as soon as the customer submits
The deposit socket resolves the pending transaction by the signed-in user and the reference, so this is an authentication problem rather than a deposit problem. Have the customer sign in again and retry.
The deposit is visible on Binance but never credits
Three things to check, in order:
- The status. Only a deposit Binance reports as
okis credited. - The hash. Internal Binance transfers arrive labelled
Off-chain transfer <id>rather than as a chain hash. The matcher handles that wrapper, but the customer must paste the string as Binance shows it. - The currency. If the matched deposit is a different asset than the wallet the request was opened against, it is refused and the request is deleted.
The live poll runs every 15 seconds for 30 minutes. After that a wallet cron job re-checks pending deposits against Binance's history, so a customer who closed the browser is not abandoned — just slower.
A deposit was marked "expired"
The depositExpiration setting is enabled. With it on, a matched deposit is
rejected if it landed more than 15 minutes either side of the request being
created, or more than 45 minutes ago. Slow chains routinely breach that. Turn it
off unless you have a specific reason for it.
A deposit was marked failed for netting nothing
Binance kept a deposit fee equal to or larger than the transfer. Crediting zero is rejected by the wallet service, so the transaction is failed with an explanation rather than retried forever.
Withdrawals
Approved withdrawals fail immediately and the customer is credited back
Almost always the API key. Binance only permits withdrawals from keys that are restricted to specific IP addresses, so a key with the withdrawal permission but no allowlist will be refused every time.
Check, in order: the withdrawal permission is enabled; the key is IP-restricted; the allowlisted address is your server's real egress IP, or your proxy's.
"Insufficient exchange balance. Available: X, Required: Y"
Your Binance spot balance is short. The pre-flight check reads the free spot balance only — funds in Earn, in Funding, in a sub-account, or held by an open order on your own account are invisible to it.
Unlike the KuCoin path, the Binance path performs no internal transfer before withdrawing. Move funds into spot on Binance and retry.
A withdrawal is stuck in PROCESSING
That state means the wallet was debited and the exchange call may or may not have been made — the deliberate design for a crash between the two. A reconciler cron sweeps those rows against Binance's withdrawal history and either confirms or refunds them. It caps how many it scans per run, so a backlog clears over several runs.
Withdrawals work on one network and not another
The network name comes from the currency import. If Binance renamed a network, or you imported before a network was added, re-run the spot currency import.
Every withdrawal to a customer address fails
If your Binance account restricts withdrawals to whitelisted destination addresses, arbitrary customer addresses will always be refused. That account setting is incompatible with self-service withdrawals.
When to restart, and what
| You changed | Restart |
|---|---|
APP_BINANCE_API_KEY or APP_BINANCE_API_SECRET |
backend and cron |
| The proxy URL, from the admin panel | Nothing — saving evicts the cached connection |
| The active provider, from the admin panel | Nothing |
NEXT_PUBLIC_EXCHANGE |
Rebuild the frontend |
| Market or currency rows | Nothing |
pm2 restart backend cron
pm2 logs backend --lines 200 | grep -i "EXCHANGE\|SPOT_DEPOSIT\|WITHDRAW"The cron worker is a separate process with its own connection. Restarting only the backend leaves the price job, the deposit verifier and the withdrawal reconciler on the old credentials.