neondatabase/neon · error

This command is not a clean node decommission, and uncleanly

Error message

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.

What it means

storcon_cli's node-drop command POSTs debug/v1/node/{node_id}/drop and removes all controller state for the node without checking whether tenants still refer to it — it is not a clean decommission. The --unclean flag is a mandatory confirmation; without it the command bails before making any request.

Source

Thrown at control_plane/storcon_cli/src/main.rs:953

                .await?;
        }
        Command::TenantDrop { tenant_id, unclean } => {
            if !unclean {
                anyhow::bail!(
                    "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."
                )
            }
            storcon_client
                .dispatch::<(), ()>(
                    Method::POST,
                    format!("debug/v1/tenant/{tenant_id}/drop"),
                    None,
                )
                .await?;
        }
        Command::NodeDrop { node_id, unclean } => {
            if !unclean {
                anyhow::bail!(
                    "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."
                )
            }
            storcon_client
                .dispatch::<(), ()>(Method::POST, format!("debug/v1/node/{node_id}/drop"), None)
                .await?;
        }
        Command::NodeDelete { node_id } => {
            eprintln!("Warning: This command is obsolete and will be removed in a future version");
            eprintln!("Use `NodeStartDelete` instead, if possible");
            storcon_client
                .dispatch::<(), ()>(Method::DELETE, format!("control/v1/node/{node_id}"), None)
                .await?;
        }
        Command::NodeStartDelete { node_id, force } => {
            let query = if force {
                format!("control/v1/node/{node_id}/delete?force=true")
            } else {

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Use the clean decommission path instead: storcon_cli node start-delete / NodeStartDelete, which drains the node safely
  2. If you accept the risk of dangling controller state, re-run node-drop with --unclean
  3. After an unclean drop, expect to repair tenant placement for shards that referenced the dropped node

Example fix

# before
storcon_cli node-drop --node-id <id>
# after (only if unclean drop is intended)
storcon_cli node-drop --node-id <id> --unclean
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Running storcon_cli node-drop without --unclean. The guard triggers purely on the missing flag, regardless of whether tenants reference the node.

Common situations: Operators using node-drop where NodeStartDelete (the clean, modern decommission path) is intended; automation written against the debug endpoint; decommissioning a node that still hosts attached shards and breaking tenant placement.

Related errors


AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16). Data as JSON: /api/errors/674cb73e42e29af3. Report an issue: GitHub.