{"record":{"id":"f5f1481c2e6ea849","repo":"influxdata/influxdb","slug":"invalid-stop-ack-for-node-node-id-current-state-current","errorCode":null,"errorMessage":"invalid stop ack for node '{node_id}' (current state: {current_state})","messagePattern":"invalid stop ack for node '(.+?)' \\(current state: (.+?)\\)","errorType":"error_code","errorClass":"CatalogError","httpStatus":null,"severity":"error","filePath":"influxdb3_catalog/src/error.rs","lineNumber":311,"sourceCode":"\n    #[error(\"cannot modify internal db\")]\n    CannotModifyInternalDatabase,\n\n    #[error(\"tried to stop a node ({node_id}) that is already stopped\")]\n    NodeAlreadyStopped { node_id: Arc<str> },\n\n    #[error(\n        \"node '{node_id}' is not fully stopped (current state: {current_state}); run \\\"stop node\\\" first\"\n    )]\n    NodeNotFullyStopped {\n        node_id: Arc<str>,\n        current_state: &'static str,\n    },\n\n    #[error(\"node '{node_id}' has compact mode and cannot be removed\")]\n    NodeModeNotRemovable { node_id: Arc<str> },\n\n    #[error(\"invalid stop ack for node '{node_id}' (current state: {current_state})\")]\n    InvalidStopAck {\n        node_id: Arc<str>,\n        current_state: &'static str,\n    },\n\n    #[error(\"invalid unregister for node '{node_id}' (current state: {current_state})\")]\n    InvalidUnregister {\n        node_id: Arc<str>,\n        current_state: &'static str,\n    },\n\n    #[error(\"idempotent no-op\")]\n    IdempotentNoOp,\n\n    #[error(\"cannot delete operator token\")]\n    CannotDeleteOperatorToken,\n\n    #[error(","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/influxdb3_catalog/src/error.rs#L293-L329","documentation":"Raised when a node sends a stop acknowledgement that does not match its current lifecycle state in the catalog. The node state machine expects stop acks only from nodes in an eligible state (e.g. stopping); an ack from a node already stopped, running, or in another state is rejected as invalid.","triggerScenarios":"Posting a stop-ack (heartbeat/stop acknowledgment) for a node_id whose catalog state is not one that accepts stop acks; duplicated or stale stop acks delivered after the transition already completed.","commonSituations":"Retried HTTP stop-ack requests after the first succeeded; split-brain or stale node processes acking after manual intervention; orchestration tooling replaying old requests.","solutions":["Check the node's current state in the catalog and only send the stop ack when the state machine expects it.","Treat repeated 'idempotent no-op' vs invalid-state errors: if the transition already happened, skip resending the ack.","Ensure only one orchestrator instance drives node stop operations to avoid duplicate acks.","Restart the node lifecycle flow from a clean state if state tracking has drifted."],"exampleFix":"// before\nclient.post_stop_ack(node_id).await?;\n// after\nlet state = catalog.node_state(node_id)?.current_state;\nif state == \"stopping\" {\n    client.post_stop_ack(node_id).await?;\n}","handlingStrategy":"validation","validationCode":"let state = catalog.node_state(node_id)?.current_state;\nif state != \"stopping\" {\n    return Err(format!(\"stop ack invalid in state {state}\"));\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(CatalogError::InvalidStopAck { current_state, .. }) => {\n        log::warn!(\"stale stop ack; node state={current_state}\");\n    }\n    other => other?,\n}","preventionTips":["Only ack stops from the stopping state","De-duplicate retried ack requests","Single orchestrator owns lifecycle transitions"],"tags":["cluster","node-lifecycle","state-machine"],"backgroundTag":"invalid-state-transition","analyzedSha":"06200ef96ba82c5f6727e5038a83af8e722c6875","analyzedAt":"2026-09-19T12:55:30.003Z","contentChangedAt":"2026-09-19T12:55:30.003Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}