cloudflare/pingora · error · std::io::Error

dial9 s3 service_name must not be empty

Error message

dial9 s3 service_name must not be empty

What it means

Companion check to the bucket validation in build_dial9_runtime() (pingora-runtime/src/lib.rs:371): with the dial9-worker-s3 feature and s3_upload configured, the service_name used for S3 request signing must be a non-empty string after trimming. An empty service name would make signing ambiguous, so construction returns ErrorKind::InvalidInput.

Source

Thrown at pingora-runtime/src/lib.rs:371

    let mut traced = TracedRuntime::builder()
        .with_trace_path(opts.trace_path.clone())
        .with_runtime_name(runtime_name)
        .with_task_tracking(opts.task_tracking);
    if let Some(worker_poll_interval) = opts.worker_poll_interval {
        traced = traced.with_worker_poll_interval(worker_poll_interval);
    }

    #[cfg(feature = "dial9-worker-s3")]
    if let Some(s3_upload) = &opts.s3_upload {
        if s3_upload.bucket.trim().is_empty() {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                "dial9 s3 bucket must not be empty",
            ));
        }
        if s3_upload.service_name.trim().is_empty() {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                "dial9 s3 service_name must not be empty",
            ));
        }
        let s3_config = dial9_tokio_telemetry::background_task::s3::S3Config::builder()
            .bucket(s3_upload.bucket.clone())
            .service_name(s3_upload.service_name.clone())
            .maybe_prefix(s3_upload.prefix.clone())
            .maybe_region(s3_upload.region.clone())
            .maybe_instance_path(s3_upload.instance_path.clone());
        let traced = traced.with_s3_uploader(s3_config.build());
        if let Some(client) = s3_upload.client.clone() {
            return traced
                .with_s3_client(client)
                .build_and_start(builder, writer);
        }
        return traced.build_and_start(builder, writer);
    }

View on GitHub (pinned to 0046038bd4)

Solutions

  1. Set service_name explicitly, normally "s3" for AWS S3 and S3-compatible stores
  2. For non-AWS endpoints keep "s3" unless the provider documents otherwise
  3. Validate bucket + service_name as a pair wherever S3 upload config is parsed

Example fix

// before
s3_upload: Some(S3Upload { bucket: "my-trace-bucket".into(), service_name: String::new(), ..Default::default() })

// after
s3_upload: Some(S3Upload { bucket: "my-trace-bucket".into(), service_name: "s3".into(), ..Default::default() })
Defensive patterns

Strategy: validation

Validate before calling

if let Some(s3) = &opts.s3_upload {
    if s3.service_name.trim().is_empty() {
        return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "s3 service_name must be set"));
    }
}

Prevention

When it happens

Trigger: Dial9RuntimeOpts with s3_upload = Some(...) where service_name is empty or whitespace, under the dial9-worker-s3 feature; validated at dial9 runtime construction right after the bucket check.

Common situations: S3 block configured with only bucket/region while service_name was assumed to default; non-AWS endpoints (MinIO etc.) where the field seems irrelevant but is still required; config templating that omits the key.

Related errors


AI-assisted analysis of cloudflare/pingora@0046038bd4 (2026-08-16). Data as JSON: /api/errors/31cf02bb05ba3fc6. Report an issue: GitHub.