{"id":"b5fa546e2c661188","repo":"pika/pika","slug":"cannot-abort-before-starting","errorCode":null,"errorMessage":"Cannot abort before starting.","messagePattern":"Cannot abort before starting\\.","errorType":"exception","errorClass":"AMQPConnectorWrongState","httpStatus":null,"severity":"error","filePath":"pika/adapters/utils/connection_workflow.py","lineNumber":237,"sourceCode":"        self._stack_timeout_ref = None\n        if self._conn_params.stack_timeout is not None:\n            self._stack_timeout_ref = self._nbio.call_later(\n                self._conn_params.stack_timeout, self._on_overall_timeout)\n\n    def abort(self) -> None:\n        \"\"\"\n        Abort the workflow asynchronously.\n\n        The completion callback will be called with an instance of AMQPConnectorAborted.\n\n        NOTE: we can't cancel/close synchronously because aborting pika\n        Connection and its transport requires an asynchronous operation.\n\n        :raises AMQPConnectorWrongState: If called after completion has been\n            reported or the workflow not started yet.\n        \"\"\"\n        if self._state == self._STATE_INIT:\n            raise AMQPConnectorWrongState('Cannot abort before starting.')\n\n        if self._state == self._STATE_DONE:\n            raise AMQPConnectorWrongState(\n                'Cannot abort after completion was reported')\n\n        self._state = self._STATE_ABORTING\n        self._deactivate()\n\n        assert self._conn_params is not None\n        assert self._nbio is not None\n        _LOG.info(\n            'AMQPConnector: beginning client-initiated asynchronous '\n            'abort; %r/%s', self._conn_params.host, self._addr_record)\n\n        if self._amqp_conn is None:\n            _LOG.debug('AMQPConnector.abort(): no connection, so just '\n                       'scheduling completion report via I/O loop.')\n            self._nbio.add_callback_threadsafe(","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/pika/pika/blob/295ad9e5795061d759b694ab1fcb33cd381d8c49/pika/adapters/utils/connection_workflow.py#L219-L255","documentation":"Raised by AMQPConnector.abort() (connection_workflow.py:224) when its internal state is _STATE_INIT, meaning start() has not yet been invoked on this connector. pika's connector is a state machine and aborting before start is a programming error because there is no I/O loop task or transport to tear down. It is surfaced as AMQPConnectorWrongState, a pika.exceptions-derived class.","triggerScenarios":"Calling connector.abort() on a freshly constructed AMQPConnector before calling its start() method. Typically happens in custom workflows or tests that instantiate AMQPConnector directly and call abort() in a finally block before start ran (e.g. because an earlier setup step raised).","commonSituations":"Test teardown calling abort() unconditionally in tearDown; exception handlers that abort a connector whose start() was skipped due to an upstream error; misuse of the internal AMQPConnector API instead of the public adapter API.","solutions":["Only call abort() after start() has been called; track a 'started' flag.","In cleanup/finally blocks, guard with: if connector is not None and started: connector.abort().","Prefer the public adapter API (Connection.connect / ioloop-based) which manages the connector lifecycle for you."],"exampleFix":"# before\nconnector = AMQPConnector(...)\ntry:\n    do_setup()\n    connector.start(...)\nfinally:\n    connector.abort()  # raises if do_setup() threw\n\n# after\nconnector = AMQPConnector(...)\nstarted = False\ntry:\n    do_setup()\n    connector.start(...)\n    started = True\nfinally:\n    if started:\n        connector.abort()","handlingStrategy":"validation","validationCode":"started = False\nconnector = AMQPConnector(...)\ntry:\n    connector.start(...)\n    started = True\nfinally:\n    if started:\n        connector.abort()","typeGuard":"def can_abort(connector) -> bool:\n    # AMQPConnector exposes its state via _state; INIT means not started.\n    return getattr(connector, '_state', None) != connector._STATE_INIT and \\\n           getattr(connector, '_state', None) != connector._STATE_DONE","tryCatchPattern":"from pika.adapters.utils.connection_workflow import AMQPConnectorWrongState\n\ntry:\n    connector.abort()\nexcept AMQPConnectorWrongState as e:\n    if 'Cannot abort before starting' in str(e):\n        logger.debug('connector never started; nothing to abort')\n    else:\n        raise","preventionTips":["Track a 'started' flag and only abort when it is set.","Prefer the public adapter API which manages the connector lifecycle for you.","In tests, set connector = None until start() succeeds and guard abort with 'if connector is not None'."],"tags":["connection-workflow","state-machine","amqp-connector","lifecycle"],"analyzedSha":"295ad9e5795061d759b694ab1fcb33cd381d8c49","analyzedAt":"2026-08-04T20:47:41.389Z","schemaVersion":2}