freqtrade/freqtrade · error · InvalidOrderException
Could not cancel order. Message: {e}
Error message
Could not cancel order. Message: {e} What it means
freqtrade wraps ccxt.InvalidOrder from _api.cancel_order() into InvalidOrderException('Could not cancel order'). The exchange refused the cancel because the order is in a terminal state (already filled or canceled) or the id is invalid for that pair. Freqtrade's own cancel handling treats this as 'order effectively gone' in most paths.
Source
Thrown at freqtrade/exchange/exchange.py:1801
def cancel_order(self, order_id: str, pair: str, params: dict | None = None) -> dict[str, Any]:
if self._config["dry_run"]:
try:
order = self.fetch_dry_run_order(order_id)
order.update({"status": "canceled", "filled": 0.0, "remaining": order["amount"]})
return order
except InvalidOrderException:
return {}
if params is None:
params = {}
try:
order = self._api.cancel_order(order_id, pair, params=params)
self._log_exchange_response("cancel_order", order)
order = self._order_contracts_to_amount(order)
return order
except ccxt.InvalidOrder as e:
raise InvalidOrderException(f"Could not cancel order. Message: {e}") from e
except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e
except (ccxt.OperationFailed, ccxt.ExchangeError) as e:
raise TemporaryError(
f"Could not cancel order due to {e.__class__.__name__}. Message: {e}"
) from e
except ccxt.BaseError as e:
raise OperationalException(e) from e
def cancel_stoploss_order(self, order_id: str, pair: str, params: dict | None = None) -> dict:
if self.get_option("stoploss_query_requires_stop_flag"):
params = params or {}
params["stop"] = True
return self.cancel_order(order_id, pair, params)
def is_cancel_order_result_suitable(self, corder) -> TypeGuard[CcxtOrder]:
if not isinstance(corder, dict):
return FalseView on GitHub (pinned to 1c8edfe4d1)
Solutions
- Treat the exception as 'order no longer open': re-fetch the order (fetch_order) to learn its final state (filled/canceled) instead of retrying the cancel.
- Use freqtrade's handle_insufficient_funds / cancel-order-then-verify flow: catch InvalidOrderException and return {} (freqtrade's own safe_cancel_order does exactly this).
- If racing during volatility, shorten the gap between checking and canceling, or rely on freqtrade's built-in order handling rather than strategy-level cancels.
- Clean stale order ids after restarts so the bot never cancels orders it no longer owns.
Example fix
# before
order = exchange.cancel_order(order_id, pair) # raises if already filled/canceled
# after (mirrors freqtrade's own pattern)
from freqtrade.exceptions import InvalidOrderException
try:
order = exchange.cancel_order(order_id, pair)
except InvalidOrderException:
# Order already gone - fetch its final state
try:
order = exchange.fetch_order(order_id, pair)
except Exception:
order = {"status": "canceled", "id": order_id} Defensive patterns
Strategy: try-catch
Validate before calling
corder = next((o for o in exchange.fetch_open_orders(pair) if o["id"] == order_id), None)
if corder is None:
# nothing to cancel - avoid InvalidOrderException
pass Type guard
from freqtrade.exceptions import InvalidOrderException
def order_gone_after_cancel_error(e: BaseException) -> bool:
"""InvalidOrderException during cancel means the order is (already) not cancellable."""
return isinstance(e, InvalidOrderException) Try / catch
from freqtrade.exceptions import InvalidOrderException
try:
exchange.cancel_order(order_id, pair)
except InvalidOrderException:
# already filled or canceled - reconcile state via fetch
order = exchange.fetch_order(order_id, pair)
if order.get("status") == "closed":
... # handle the fill instead of the cancel Prevention
- Check the order is still open (fetch_open_orders) right before canceling when races matter.
- Never cancel order ids from previous sessions without verifying ownership/state.
- Avoid manual cancels in the exchange UI while the bot runs.
When it happens
Trigger: Calling cancel_order / cancel_stoploss_order for an order that was just filled (race: fill happened between your check and the cancel), an order already canceled manually on the exchange website, or an order id belonging to another pair.
Common situations: High-volatility races where stoploss-on-exchange fills as freqtrade tries to cancel it; user manually cancels orders in the exchange UI while the bot runs; freqtrade restarted with stale order ids in its DB.
Related errors
- Could not cancel order due to {e.__class__.__name__}. Messag
- Trade history not available for {exchange.name}. You cannot
- Historic data not available for {exchange.name}. {exchange.n
- Historic klines not available for {exchange.name}. Please us
- Could not combine {curr_1} and {curr_2} to get a valid pair.
AI-assisted analysis of freqtrade/freqtrade@1c8edfe4d1 (2026-08-15).
Data as JSON: /api/errors/234ebba8d763503b.
Report an issue: GitHub.