neondatabase/neon · error
Safekeeper set up for auth but no private key specified
Error message
Safekeeper set up for auth but no private key specified
What it means
storcon talks to safekeepers over their HTTP API. When any safekeeper in the local env has auth enabled, storcon must sign JWTs for those requests, which requires a private key; if the storage controller was configured without one, argument construction bails before the process is even started.
Source
Thrown at control_plane/src/storage_controller.rs:636
if let Some(lag) = self.config.max_secondary_lag_bytes.as_ref() {
args.push(format!("--max-secondary-lag-bytes={lag}"))
}
if let Some(threshold) = self.config.long_reconcile_threshold {
args.push(format!(
"--long-reconcile-threshold={}",
humantime::Duration::from(threshold)
))
}
args.push(format!(
"--neon-local-repo-dir={}",
self.env.base_data_dir.display()
));
if self.env.safekeepers.iter().any(|sk| sk.auth_enabled) && self.private_key.is_none() {
anyhow::bail!("Safekeeper set up for auth but no private key specified");
}
if self.config.timelines_onto_safekeepers {
args.push("--timelines-onto-safekeepers".to_string());
}
// neon_local is used in test environments where we often have less than 3 safekeepers.
if self.config.timeline_safekeeper_count.is_some() || self.env.safekeepers.len() < 3 {
let sk_cnt = self
.config
.timeline_safekeeper_count
.unwrap_or(self.env.safekeepers.len());
args.push(format!("--timeline-safekeeper-count={sk_cnt}"));
}
if let Some(duration) = self.config.shard_split_request_timeout {
args.push(format!(View on GitHub (pinned to 8f60b04da4)
Solutions
- Generate a JWT key pair and configure the storage controller's private key (config private_key / CLI key option)
- Or disable safekeeper auth in the env config for local development
Defensive patterns
Strategy: validation
Validate before calling
let auth_used = env.safekeepers.iter().any(|sk| sk.auth_enabled);
anyhow::ensure!(
!auth_used || private_key.is_some(),
"safekeeper auth enabled but the storage controller has no private key"
); Prevention
- Provision the JWT key pair whenever safekeeper auth is enabled
- Keep auth disabled for purely local runs
- Add a config lint that fails early on this inconsistency
When it happens
Trigger: The env config enables safekeeper auth (auth_enabled on any safekeeper) while the storage controller has no private key configured (missing private_key in config or on the CLI).
Common situations: Turning on JWT auth for safekeepers in a local env but forgetting to provision the storcon key pair, or reusing an old env config after auth support was introduced.
Related errors
- path is neither a directory or a file
- Configured for JWT auth with zero decoding keys. All JWT gat
- Failed to check node status: {e}
- Postgres directory '{}' not found in {}
- setting scheduling policy unsuccessful for safekeeper {node_
AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16).
Data as JSON: /api/errors/720fd34f03c10c36.
Report an issue: GitHub.