risingwavelabs/risingwave · error · ConnectorError

Both `access_key` and `secret_key` must be provided

Error message

Both `access_key` and `secret_key` must be provided

What it means

Thrown by `build_credential_provider` in connector_common/common.rs when static AWS credentials are expected but only one of `access_key`/`secret_key` is set, default credential providers are disabled (RW_DISABLE_DEFAULT_CREDENTIAL env true), and no complete static pair is available. The AWS SDK requires both parts of a static credential pair.

Source

Thrown at src/connector/src/connector_common/common.rs:159

    }

    async fn build_credential_provider(&self) -> ConnectorResult<SharedCredentialsProvider> {
        if let (Some(access_key), Some(secret_key)) =
            (self.access_key.as_ref(), self.secret_key.as_ref())
        {
            Ok(SharedCredentialsProvider::new(
                aws_credential_types::Credentials::from_keys(
                    access_key,
                    secret_key,
                    self.session_token.clone(),
                ),
            ))
        } else if !env_var_is_true(DISABLE_DEFAULT_CREDENTIAL) {
            Ok(SharedCredentialsProvider::new(
                aws_config::default_provider::credentials::default_provider().await,
            ))
        } else {
            bail!("Both `access_key` and `secret_key` must be provided")
        }
    }

    async fn with_role_provider(
        &self,
        credential: SharedCredentialsProvider,
    ) -> ConnectorResult<SharedCredentialsProvider> {
        if let Some(role_name) = &self.arn {
            let region = self.build_region().await?;
            let mut role = AssumeRoleProvider::builder(role_name)
                .session_name("RisingWave")
                .region(region);
            if let Some(id) = &self.external_id {
                role = role.external_id(id);
            }
            let provider = role.build_from_provider(credential).await;
            Ok(SharedCredentialsProvider::new(provider))
        } else {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Provide both `access_key` and `secret_key` in the connector's secret/props.
  2. If you intend to use the environment/instance-role credential chain, do not disable default credentials (leave RW_DISABLE_DEFAULT_CREDENTIAL unset/false) and remove the partial static keys.
  3. Check the mounted secret/parameters store entry actually contains both fields.

Example fix

// before
props: { access_key: "AKIA..." } // secret_key missing
// after
props: { access_key: "AKIA...", secret_key: "..." }
Defensive patterns

Strategy: validation

Validate before calling

function validateAwsStaticCreds(props) {
  const hasAk = !!props.access_key, hasSk = !!props.secret_key;
  if (hasAk !== hasSk) throw new Error('access_key and secret_key must both be set (or both omitted)');
}
validateAwsStaticCreds(withProps);

Type guard

const hasPair = (p) => typeof p.access_key === 'string' && p.access_key.length > 0 && typeof p.secret_key === 'string' && p.secret_key.length > 0;

Try / catch

try { await createSink(cfg); } catch (e) { if (String(e).includes('Both `access_key` and `secret_key`')) { fixSecrets(cfg); return createSink(cfg); } throw e; }

Prevention

When it happens

Trigger: Building an AWS config for a sink/source with `access_key` set but `secret_key` missing (or vice versa) while default credential chain lookup is disabled.

Common situations: Partial secret injection (only one key mounted), copy-pasting a config template and forgetting the secret_key line, or intentionally disabling IMDS/env default credentials then supplying incomplete static creds.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/5e32f268d1d047b9. Report an issue: GitHub.