neondatabase/neon · error

Supply either config file path or --config=inline-config

Error message

Supply either config file path or --config=inline-config

What it means

endpoint_storage's main() requires exactly one source of configuration: a positional config file path or --config=<inline JSON>. When neither is supplied, it bails with this message before binding its listener. The chosen string is parsed as JSON into Config (parsing failures surface as a separate 'parsing config' context error).

Source

Thrown at endpoint_storage/src/main.rs:61

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    logging::init(
        logging::LogFormat::Plain,
        logging::TracingErrorLayerEnablement::EnableWithRustLogFilter,
        logging::Output::Stdout,
    )?;

    let args = Args::parse();
    let config: Config = if let Some(config_path) = args.config_file {
        info!("Reading config from {config_path}");
        let config = std::fs::read_to_string(config_path)?;
        serde_json::from_str(&config).context("parsing config")?
    } else if let Some(config) = args.config {
        info!("Reading inline config");
        serde_json::from_str(&config).context("parsing config")?
    } else {
        anyhow::bail!("Supply either config file path or --config=inline-config");
    };

    info!("Reading pemfile from {}", config.pemfile.clone());
    let pemfile = std::fs::read(config.pemfile.clone())?;
    info!("Loading public key from {}", config.pemfile.clone());
    let auth = endpoint_storage::JwtAuth::new(&pemfile)?;

    let listener = tokio::net::TcpListener::bind(config.listen).await.unwrap();
    info!("listening on {}", listener.local_addr().unwrap());

    let storage =
        remote_storage::GenericRemoteStorage::from_storage_kind(config.storage_kind).await?;
    let cancel = tokio_util::sync::CancellationToken::new();
    if !args.no_s3_check_on_startup {
        app::check_storage_permissions(&storage, cancel.clone()).await?;
    }

    let proxy = std::sync::Arc::new(endpoint_storage::Storage {

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Pass a config file path as the positional argument: endpoint_storage /path/to/config.json
  2. Or pass inline JSON: endpoint_storage --config='{"pemfile": ..., "listen": ..., "storage_kind": ...}'
  3. Check the container command/args in the helm chart or unit file to confirm the argument actually reaches the process

Example fix

# before
./endpoint_storage --no-s3-check-on-startup
# after
./endpoint_storage --config='{"pemfile":"/certs/jwt.pem","listen":"0.0.0.0:51243","storage_kind":{"S3":{"bucket_name":"b","bucket_region":"r","prefix_in_bucket":"p"}}}'
Defensive patterns

Strategy: validation

Validate before calling

# shell wrapper: refuse to launch without config
if [ -z "$1" ] && [ -z "$ENDPOINT_STORAGE_CONFIG" ]; then
  echo "error: supply a config file path or --config=INLINE_JSON" >&2
  exit 2
fi
exec ./endpoint_storage "${1:-}" ${ENDPOINT_STORAGE_CONFIG:+--config=$ENDPOINT_STORAGE_CONFIG}

Prevention

When it happens

Trigger: Launching the endpoint_storage binary with no positional config file argument and no --config flag; passing only unrelated flags like --no-s3-check-on-startup (which itself requires --config).

Common situations: Kubernetes/helm chart misconfiguration dropping the args; running the binary by hand without reading usage; wrappers that quote away or drop the config argument.

Related errors


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