neondatabase/neon · error
Tenant shard not found
Error message
Tenant shard not found
What it means
watch_tenant_shard fetched the tenant description (GET control/v1/tenant/{tenant_id}) successfully, but no entry in desc.shards has a tenant_shard_id equal to the requested one. The tenant exists, but the specific shard (tenant id + shard number + count) does not. The command bails with this anyhow error from the Option::ok_or.
Source
Thrown at control_plane/storcon_cli/src/main.rs:1449
"Waiting for tenant shard {tenant_shard_id} to be migrated to node {until_migrated_to}"
);
}
loop {
let desc = storcon_client
.dispatch::<(), TenantDescribeResponse>(
Method::GET,
format!("control/v1/tenant/{}", tenant_shard_id.tenant_id),
None,
)
.await?;
// Output the current state of the tenant shard
let shard = desc
.shards
.iter()
.find(|s| s.tenant_shard_id == tenant_shard_id)
.ok_or(anyhow::anyhow!("Tenant shard not found"))?;
let summary = format!(
"attached: {} secondary: {} {}",
shard
.node_attached
.map(|n| format!("{n}"))
.unwrap_or("none".to_string()),
shard
.node_secondary
.iter()
.map(|n| n.to_string())
.collect::<Vec<_>>()
.join(","),
if shard.is_reconciling {
"(reconciler active)"
} else {
"(reconciler idle)"
}
);View on GitHub (pinned to 8f60b04da4)
Solutions
- Describe the tenant and list its actual shards (their shard numbers and shard count) to get a valid tenant_shard_id
- For an unsharded tenant, use shard number 0 with the unsharded count (e.g. <tenant_id>-0000 style id)
- Re-check the tenant_shard_id for typos and confirm it comes from the same storage controller
Example fix
# before: tenant is unsharded, only shard 0 exists storcon_cli tenant-shard-watch --tenant-shard-id <tenant_id>-0002-8 # after storcon_cli tenant-shard-watch --tenant-shard-id <tenant_id>-0000
Defensive patterns
Strategy: validation
Validate before calling
// Validate the tenant_shard_id against the describe response before watching
let desc: TenantDescribeResponse = client
.dispatch(Method::GET, format!("control/v1/tenant/{}", tenant_shard_id.tenant_id), None)
.await?;
anyhow::ensure!(
desc.shards.iter().any(|s| s.tenant_shard_id == *tenant_shard_id),
"shard {} not present; available shards: {:?}",
tenant_shard_id,
desc.shards.iter().map(|s| s.tenant_shard_id.to_string()).collect::<Vec<_>>()
); Type guard
fn shard_exists(desc: &TenantDescribeResponse, id: &TenantShardId) -> bool {
desc.shards.iter().any(|s| s.tenant_shard_id == *id)
} Prevention
- Always resolve shard ids from a fresh tenant describe rather than caching them across resharding events
- Remember unsharded tenants expose exactly one shard (number 0)
- Re-list shards after splits/merges before watching or migrating
When it happens
Trigger: Passing a TenantShardId whose shard number/count does not match the tenant's actual sharding — for example shard 1 of an unsharded tenant that only has shard 0, or a stale shard count after the tenant was resharded (split/merged) — to tenant-shard-watch or tenant-shard-describe.
Common situations: Watching a shard with a hardcoded id after the tenant's shard count changed; assuming a tenant is sharded when it is unsharded (only shard 0000 exists); copy-pasting a tenant_shard_id from another environment; the shard was detached or merged away between listing and watching.
Related errors
- Unknown scheduling policy '{s}', try active,essential,pause,
- Unknown availability state '{s}'
- Migration to {node} rejected, may require `--force` ({})
- AZ {} not found on any node: known AZs are: {:?}
- This command is not a tenant deletion, and uncleanly drops a
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/903745bb9527cdac.
Report an issue: GitHub.