{"record":{"id":"6231c2c6677eb829","repo":"neondatabase/neon","slug":"this-command-is-not-a-tenant-deletion-and-unclean","errorCode":null,"errorMessage":"This command is not a tenant deletion, and uncleanly drops all controller state for the tenant.  If you know what you're doing, add `--unclean` to proceed.","messagePattern":"This command is not a tenant deletion, and uncleanly drops all controller state for the tenant\\.  If you know what you're doing, add `--unclean` to proceed\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"control_plane/storcon_cli/src/main.rs","lineNumber":939,"sourceCode":"                    .map(|s| {\n                        (\n                            s.tenant_shard_id,\n                            preferred_az.clone().map(AvailabilityZone),\n                        )\n                    })\n                    .collect(),\n            };\n            storcon_client\n                .dispatch::<ShardsPreferredAzsRequest, ShardsPreferredAzsResponse>(\n                    Method::PUT,\n                    \"control/v1/preferred_azs\".to_string(),\n                    Some(req),\n                )\n                .await?;\n        }\n        Command::TenantDrop { tenant_id, unclean } => {\n            if !unclean {\n                anyhow::bail!(\n                    \"This command is not a tenant deletion, and uncleanly drops all controller state for the tenant.  If you know what you're doing, add `--unclean` to proceed.\"\n                )\n            }\n            storcon_client\n                .dispatch::<(), ()>(\n                    Method::POST,\n                    format!(\"debug/v1/tenant/{tenant_id}/drop\"),\n                    None,\n                )\n                .await?;\n        }\n        Command::NodeDrop { node_id, unclean } => {\n            if !unclean {\n                anyhow::bail!(\n                    \"This command is not a clean node decommission, and uncleanly drops all controller state for the node, without checking if any tenants still refer to it.  If you know what you're doing, add `--unclean` to proceed.\"\n                )\n            }\n            storcon_client","sourceCodeStart":921,"sourceCodeEnd":957,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/control_plane/storcon_cli/src/main.rs#L921-L957","documentation":"storcon_cli's tenant-drop command is a debug escape hatch: it POSTs debug/v1/tenant/{tenant_id}/drop and deletes all controller state for the tenant without doing a proper tenant deletion (no pageserver/remote-storage cleanup coordination). The --unclean flag is a mandatory confirmation; without it the command bails before making any request.","triggerScenarios":"Running storcon_cli tenant-drop without --unclean. The guard triggers purely on the missing flag, regardless of tenant state.","commonSituations":"Operators reaching for tenant-drop expecting a normal deletion workflow; leftover automation scripts from older versions that do not pass --unclean; using it on a tenant that is still live when a graceful deletion path (control-plane tenant deletion) should be used instead.","solutions":["If you truly want to uncleanly drop controller state, re-run with --unclean","Prefer the regular tenant deletion flow when the tenant still exists end-to-end (pageserver, remote storage)","Clean up any orphaned pageserver/remote-storage data afterwards, since this path drops controller state only"],"exampleFix":"# before\nstorcon_cli tenant-drop --tenant-id <id>\n# after\nstorcon_cli tenant-drop --tenant-id <id> --unclean","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Gate tenant-drop behind an explicit operator confirmation step in tooling","Prefer the standard tenant deletion API; reserve --unclean for broken controller state","After an unclean drop, schedule cleanup of orphaned pageserver and remote-storage data"],"tags":["storcon","destructive-command","confirmation-flag","cli"],"backgroundTag":"confirmation-flag-required","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}