Binance CM-UM Integration and dualSidePosition: The Complete -4531 Handling Guide
c
Your strategy has been running fine for six months. Then, sometime after 2026-06-30, a dualSidePosition flip gets rejected by the webhook with{"code":-4531,"msg":"Position mode change requires syncing UM and CM..."}— telling you to close positions or orders on the CM side. But you don't even trade coin-margined. The reason: the Binance CM-UM integration for dualSidePosition went fully live on 06-30.
Here's what nobody warned you about: starting 2026-06-30, Binance folded COIN-M (CM / DAPI) into the unified USDⓈ-M (UM / FAPI) architecture, and dualSidePosition is now a single account-wide value. Change UM and CM changes with it, and vice versa. What you thought was "flip UM's mode" now checks whether anything is hanging around on CM — and if there is, the whole request gets bounced with -4531.
This post isn't a summary of the full integration notice — the notice has four sections (A / B / C / D) aimed at different endpoint users. This post is about one thing: what flipping position mode now runs into, and how you work around it— plus a detail most people miss: -4531 is explicitly a temporary error according to Binance, but that doesn't mean you can ignore it today.
-4531 is live right now and will disappear once CM enters Guard — but in the meantime, orphan CM orders and positions block every mode-change request you send. Second, hard-coding "retry a few times and it'll pass" is wrong — if the CM side isn't clean, it will never pass. Third, since 2026-06-29 09:00 UTC, the COIN-M auto-cancel countdown has been suspended, so any strategy that relied on it for kill-switch protection has zero coverage during the maintenance window.What Actually Got Integrated — One Word: Shared
On 2026-06-10 Binance published the "Important CM-UM Integration Notice" (verified July 2026). The opening paragraph tells you the whole story: COIN-M has been folded into the same unified architecture as USDⓈ-M, and a bunch of REST endpoints, WebSocket streams, and account-level behaviors are all being aligned with USDⓈ-M's existing conventions. This isn't a new feature. It's flattening the two sides into consistent behavior.
The flattening is gradual — the notice itself says "Individual changes may be enabled at different times after the initial effective date"— with full activation on 2026-06-30. So if your bot was fine before 06-30 and started seeing behavior you've never seen after, it's almost certainly one of the integration changes landing on your account.
The integration touches a lot of specifics (order acks drop avgPrice/cumQuote, CM stop-types now go through the new /dapi/v1/algoOrder, rate-limit pools merged, STP unified to UM's settings), but if you have a webhook that flips position mode, the change that hits you most directly — and is easiest to break silently — is dualSidePosition. The table below lays out the before-and-after.
| Item | Before Integration | After 2026-06-30 |
|---|---|---|
dualSidePosition | One value on UM, one on CM, independent | One value shared by UM and CM; one call changes both |
| What you need to clean before flipping mode | Only the UM side | Both UM and CM sides |
| Error codes that block you | -4067 / -4068 | Plus -4531 (fires when the CM sync fails) |
| COIN-M auto-cancel countdown | Normal | Suspended from 2026-06-29 09:00 UTC until CM resumes |
Sources: Binance Important CM-UM Integration Notice (published 2026-06-10) and Binance USDⓈ-M / COIN-M Futures API change-logs (verified July 2026).
Don't guess at this one. Check the CM account via dashboard or API for any open positions or orders — if none, you're fine; if any, clean them first. The cleanup logic lives in the "Three Things to Confirm Before Flipping Mode" section below.
What Exactly Is -4531 Rejecting — And Why It's Not -4067 / -4068
Binance added this error code in the change-log entry dated 2026-05-11 (Effective Date 2026-05-13). The original wording is blunt:
-4531: When changing UM dualSidePosition, the system will automatically sync CM dualSidePosition. If the CM account has any open position or open order, the sync cannot proceed and the UM position mode change will be rejected with error code -4531."(Verified July 2026; source: Binance USDⓈ-M Futures API change-log, entry 2026-05-11.)
In plain English: you called a UM endpoint, but Binance internally also tries to update CM's dualSidePosition for you — and if that internal "also update CM" step fails, the UM call you originally made gets rolled back and returns -4531. The failure isn't on your side — it's in Binance's internal sync step.
So how's this different from the -4067 / -4068 you already know? The difference is they point at the same problem happening in different places. The older two mean your side (UM account) has open orders or open positions; -4531 means the other side (CM account) has open orders or open positions. The message itself won't tell you which CM symbol is stuck — you have to go query CM yourself.
| Error code | Where it's stuck | How to clean |
|---|---|---|
-4067 | UM has open orders | DELETE /fapi/v1/allOpenOrders, or cancel per symbol |
-4068 | UM has an open position | Close with a reduce-only market order, or flatten from the dashboard |
-4531 | CM has open orders or an open position (sync failed) | Send DELETE /dapi/v1/allOpenOrders first, then flatten the CM position |
Three "you can't flip mode" error codes side by side. Source: Binance USDⓈ-M Futures API change-log (verified July 2026).
There's another temporary error worth mentioning if your request lands in the middle of Binance's CM migration maintenance window: you'll get -1016 ("This service is no longer available.") or -1109 ("Invalid account."). That's not a parameter problem on your end — Binance is moving pieces around internally. Don't retry these immediately; wait for the maintenance window to end.
Binance Says -4531 Is Temporary — But You Can't Just Wait
The same change-log entry has a Note at the bottom that people often skip, but it decides how you should write your error handling:
(Same source.) Worth noting: the Binance USDⓈ-M error-code reference page (
developers.binance.com/en/docs/products/derivatives-trading-usds-futures/error-code, updated 2026-07-30) still doesn't list -4531 as of verification — which lines up with the Note's "temporary" language: Binance doesn't expect it to survive long enough to make it into the permanent error-code table.But watch out for two things. First, "approximately 1 month" doesn't say what day the clock starts from — is it the 05-13 effective date, or the 06-30 full-activation date? Binance doesn't say. In practice, treat it as "at least a month, possibly longer" and don't bet on any particular end date.
Second, even when it's gone, -4067 and -4068 aren't going anywhere— UM-side open orders and positions will still block mode changes, because that's normal behavior. So even the day you stop seeing -4531, your error-handling logic still needs to handle "clean up before flipping mode" — the scope just shrinks from UM+CM back to UM only.
So what should you actually do? Don't write logic like "on -4531, wait an hour and retry." Write "on -4531, go check CM for open orders or positions; if any, clean them and retry; if none, page a human." The difference sounds small but it decides whether your strategy self-recovers or breaks silently.
Three Things to Confirm Before Flipping Mode
Section A.1 of Binance's notice has a line labelled "Action required": "before flipping dualSidePosition, ensure both UM and CM have no open orders and no open positions." Translated into an actionable checklist:
- UM has no open orders. Call
GET /fapi/v1/openOrders. The response array must be empty. If not, hitDELETE /fapi/v1/allOpenOrders— either per symbol, or use the version without a symbol to cancel everything at once. - UM has no open positions. Call
GET /fapi/v2/positionRisk. Every row'spositionAmtmust be 0. For anything non-zero, close with a reduce-only market order or flatten from the dashboard. - Do the same two things on CM. The endpoints are
GET /dapi/v1/openOrdersandGET /dapi/v1/positionRisk. Before 2026-06-30 you didn't need this step; after, you do — every time. And when you forget, the error Binance gives you is-4531, not anything with the word UM in it.
Even after the check passes, don't flip immediately — another process might place an order in between. The check and the flip need to be atomic: wrap the whole thing in a mutex, or at least double-check open orders and positions right before you flip. After flipping, verify the new value took effect with GET /fapi/v1/positionSide/dual — don't assume a 200 response means success.
A side reminder: all of this assumes your API key has futures trading permission and the correct IP allowlist. Otherwise you'll hit -2015 (invalid API-key), which has nothing to do with -4531 but looks similar. For the full API-key setup checklist, see Binance API Key Security Setup.
The Landmine Everyone Missed — COIN-M Countdown Is Suspended
If your architecture uses POST /dapi/v1/countdownCancelAll (COIN-M's auto-cancel all open orders / countdown) as a kill-switch that cancels orders when your webhook dies, the 2026-06-29 change-log has an entry you need to see:
"Any countdown set before the suspension remains effective in the matching engine up until the snapshot is taken at maintenance shutdown. If the countdown timer set by the user is scheduled to fire after the maintenance snapshot, the countdown for those symbols will not take effect."
(Source: Binance COIN-M Futures API change-log, entry 2026-06-29, verified July 2026.)
Plain reading: any countdown you set to fire after the maintenance snapshot will not take effect. Binance hasn't committed to a resume time, and hasn't promised the behavior after resume will be identical — the notice only says "will be restored after CM resumes," an honest but very open-ended statement.
The USDⓈ-M side's POST /fapi/v1/countdownCancelAll isn't affected and can keep running. So if you were relying on the COIN-M countdown for protection and are still waiting for it to come back — first check whether your strategy has any other disconnect protection during this gap, like a server-side watchdog, or switching over to the UM countdown (worth considering if the contracts you trade are perpetuals rather than coin-margined delivery contracts). For a wider view of disconnect-failure design, see What Happens to Your Automated Strategy When TradingView or an Exchange Goes Down.
Turning All of the Above Into a Check You Can Drop Into CI
You don't actually need to bake this into your strategy code — that's too fragile and too hard to test. Split it into a "mode-flip gatekeeper function" and an "error-code routing table", and call it once right before you flip. Below is the skeleton of that gatekeeper, in Python — swap the requests calls for any language's HTTP client and the shape stays the same.
# Pseudocode skeleton illustrating the flow. Error handling, signing,
# and rate limiting are omitted — fill them in before you ship.
def ensure_side_clean(client, prefix):
"""prefix is '/fapi/v1' or '/dapi/v1'. Returns True if this side is flat."""
orders = client.get(f"{prefix}/openOrders")
if orders:
client.delete(f"{prefix}/allOpenOrders")
positions = client.get(f"{prefix}/positionRisk")
non_flat = [p for p in positions if float(p["positionAmt"]) != 0]
if non_flat:
# Don't auto-flatten here — different strategies have different rules
# for when to close, so let the caller decide.
raise NotFlatError(side=prefix, positions=non_flat)
return True
def flip_dual_side_position(client, target: bool):
ensure_side_clean(client, "/fapi/v1") # UM
ensure_side_clean(client, "/dapi/v1") # CM — mandatory after 2026-06-30
resp = client.post("/fapi/v1/positionSide/dual", params={"dualSidePosition": target})
if resp.status_code != 200:
code = resp.json().get("code")
# Error-code routing table — don't retry every code the same way
if code == -4531:
# CM sync failed — something appeared between check and flip
raise CmSyncFailed()
if code in (-4067, -4068):
raise UmNotFlat()
if code == -1016:
# Maintenance — use exponential backoff, don't hammer every minute
raise ServiceUnavailable(retry_after=300)
raise UnknownError(code=code)
# Don't assume 200 means success — verify
current = client.get("/fapi/v1/positionSide/dual")
assert current["dualSidePosition"] == targetThe point isn't the API calls — it's the error-code routing table: different codes get different retry strategies. -4531 and -4067 / -4068 are signals for "something wasn't cleaned" — you must actually clean before retrying. -1016 is a signal for "Binance is in the middle of something" — come back later. Any other code is unknown and should page a human.
The Honest Section: We Didn't Reproduce -4531
We didn't actually trigger -4531 to write this post — first, this error only fires under specific conditions (an account with concurrent UM and CM activity plus orphan orders or positions in between), and second, we don't manufacture those conditions in production just to reproduce errors for a blog post. All the timestamps, error payloads, and trigger conditions in this post come directly from Binance's official change-log and integration notice, not from our own reproduction.
Another caveat is around "approximately 1 month" — we don't have inside knowledge of when CM will enter Guard. That inference relies on the literal wording in the change-log. Before you ship to production, we recommend checking developers.binance.com's change-log and error-code reference pages yourself, especially whether -4531 has been removed from the error-code table — that would be the most direct signal that CM has entered Guard.
FAQ
I don't trade coin-margined at all — why am I hitting CM-related errors?
dualSidePosition. When you change UM, Binance internally also changes CM for you. If your account did any COIN-M trading long ago and left an un-cancelled order or an un-closed position behind, you'll hit -4531. One CM query will tell you.When will -4531 disappear entirely?
-4067 / -4068 will still block you, so "clean up before flipping mode" is logic that never goes out of date.Can I still use POST /dapi/v1/positionSide/dual?
POST /fapi/v1/positionSide/dual — either call changes both UM and CM. Binance hasn't removed the dapi endpoint, but there's no reason to prefer it; the fapi one is identical in effect.During the maintenance window I got -1016 or -1109 — should I retry immediately?
-1016 / -1109 both mean Binance is moving pieces around internally, and immediate retries just burn rate-limit points for nothing. Use exponential backoff (start at 30 seconds, double up to a 5-minute cap), or just wait for the next hour — maintenance windows are usually on fixed schedules.Can I just set the whole account to Hedge Mode once and stop flipping?
dualSidePosition doesn't need frequent changes once you set it — very few strategies actually need to flip between One-way and Hedge often. The integration's impact lands mainly on the moment you flip; if you only flip once in your life, everything after is irrelevant to you.Get started
Move flipping position mode, clearing open orders, and routing different error codes into TVSBot's execution layer — with your own API key, dry-run first, and account-level risk controls you set yourself.
Get started free- Dynamic Position Sizing for TradingView Webhook Bots: Percent-of-Equity vs Fixed Quantity
- Binance API Key Security Setup — Disable Withdraw, IP Allowlist, 2FA
- API Key Permissions Checklist for Non-Custodial Trading Bots
- TradingView Webhook Not Firing? A Full Debug Flowchart, From Alert Setup to Exchange Rejection
- Perpetual Futures vs Spot — How to Choose a Strategy, Across Four Dimensions