{"record":{"id":"33f2453a76175772","repo":"influxdata/influxdb","slug":"idempotent-no-op","errorCode":null,"errorMessage":"idempotent no-op","messagePattern":"idempotent no-op","errorType":"error_code","errorClass":"CatalogError","httpStatus":null,"severity":"info","filePath":"influxdb3_catalog/src/error.rs","lineNumber":323,"sourceCode":"        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(\n        \"cannot change the configured generation duration for level {level}; \\\n        attempted to set to {attempted:#} but its already set to {existing:#}\"\n    )]\n    CannotChangeGenerationDuration {\n        level: u8,\n        existing: Duration,\n        attempted: Duration,\n    },\n\n    #[error(\"cannot add column {name} because it already exists with type {existing}\")]\n    DuplicateColumn {\n        name: Arc<str>,","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/influxdb3_catalog/src/error.rs#L305-L341","documentation":"Signal that a requested operation was a no-op because the desired state already holds. It is not a failure of the operation's effect; the catalog returns it so callers can distinguish 'nothing changed' from a real state change. Callers can usually treat it as success.","triggerScenarios":"Issuing a lifecycle transition (stop, unregister, mode change) on a node that is already in the target state; replaying an already-applied request.","commonSituations":"Idempotent retry after a network timeout where the first request actually succeeded; declarative/orchestrator reconcilers re-asserting desired state.","solutions":["Treat IdempotentNoOp as success and continue; the desired state already holds.","Make reconciliation logic match on this variant and skip error propagation.","If you expected a change, inspect the node's current state to confirm prior success."],"exampleFix":"// before\nlet _ = catalog.stop_node(node_id).await?;\n// after\nmatch catalog.stop_node(node_id).await {\n    Ok(_) | Err(CatalogError::IdempotentNoOp) => {}, // already stopped\n    Err(e) => return Err(e.into()),\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match result {\n    Ok(_) | Err(CatalogError::IdempotentNoOp) => Ok(()),\n    Err(e) => Err(e.into()),\n}","preventionTips":["Treat IdempotentNoOp as success in reconcilers","Log it at info level for audit","Design retries knowing transitions are idempotent"],"tags":["idempotency","node-lifecycle","catalog"],"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"}