{"record":{"id":"234ebba8d763503b","repo":"freqtrade/freqtrade","slug":"could-not-cancel-order-message-e","errorCode":null,"errorMessage":"Could not cancel order. Message: {e}","messagePattern":"Could not cancel order\\. Message: (.+?)","errorType":"exception","errorClass":"InvalidOrderException","httpStatus":null,"severity":"error","filePath":"freqtrade/exchange/exchange.py","lineNumber":1801,"sourceCode":"    def cancel_order(self, order_id: str, pair: str, params: dict | None = None) -> dict[str, Any]:\n        if self._config[\"dry_run\"]:\n            try:\n                order = self.fetch_dry_run_order(order_id)\n\n                order.update({\"status\": \"canceled\", \"filled\": 0.0, \"remaining\": order[\"amount\"]})\n                return order\n            except InvalidOrderException:\n                return {}\n\n        if params is None:\n            params = {}\n        try:\n            order = self._api.cancel_order(order_id, pair, params=params)\n            self._log_exchange_response(\"cancel_order\", order)\n            order = self._order_contracts_to_amount(order)\n            return order\n        except ccxt.InvalidOrder as e:\n            raise InvalidOrderException(f\"Could not cancel order. Message: {e}\") from e\n        except ccxt.DDoSProtection as e:\n            raise DDosProtection(e) from e\n        except (ccxt.OperationFailed, ccxt.ExchangeError) as e:\n            raise TemporaryError(\n                f\"Could not cancel order due to {e.__class__.__name__}. Message: {e}\"\n            ) from e\n        except ccxt.BaseError as e:\n            raise OperationalException(e) from e\n\n    def cancel_stoploss_order(self, order_id: str, pair: str, params: dict | None = None) -> dict:\n        if self.get_option(\"stoploss_query_requires_stop_flag\"):\n            params = params or {}\n            params[\"stop\"] = True\n        return self.cancel_order(order_id, pair, params)\n\n    def is_cancel_order_result_suitable(self, corder) -> TypeGuard[CcxtOrder]:\n        if not isinstance(corder, dict):\n            return False","sourceCodeStart":1783,"sourceCodeEnd":1819,"githubUrl":"https://github.com/freqtrade/freqtrade/blob/1c8edfe4d1e8d11bd4b40e8fc3237c26c3a60e15/freqtrade/exchange/exchange.py#L1783-L1819","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\norder = exchange.cancel_order(order_id, pair)  # raises if already filled/canceled\n\n# after (mirrors freqtrade's own pattern)\nfrom freqtrade.exceptions import InvalidOrderException\ntry:\n    order = exchange.cancel_order(order_id, pair)\nexcept InvalidOrderException:\n    # Order already gone - fetch its final state\n    try:\n        order = exchange.fetch_order(order_id, pair)\n    except Exception:\n        order = {\"status\": \"canceled\", \"id\": order_id}","handlingStrategy":"try-catch","validationCode":"corder = next((o for o in exchange.fetch_open_orders(pair) if o[\"id\"] == order_id), None)\nif corder is None:\n    # nothing to cancel - avoid InvalidOrderException\n    pass","typeGuard":"from freqtrade.exceptions import InvalidOrderException\n\ndef order_gone_after_cancel_error(e: BaseException) -> bool:\n    \"\"\"InvalidOrderException during cancel means the order is (already) not cancellable.\"\"\"\n    return isinstance(e, InvalidOrderException)","tryCatchPattern":"from freqtrade.exceptions import InvalidOrderException\n\ntry:\n    exchange.cancel_order(order_id, pair)\nexcept InvalidOrderException:\n    # already filled or canceled - reconcile state via fetch\n    order = exchange.fetch_order(order_id, pair)\n    if order.get(\"status\") == \"closed\":\n        ...  # handle the fill instead of the cancel","preventionTips":["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."],"tags":["exchange","ccxt","order-management","cancel-order","race-condition"],"backgroundTag":null,"analyzedSha":"1c8edfe4d1e8d11bd4b40e8fc3237c26c3a60e15","analyzedAt":"2026-08-15T05:09:08.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}