risingwavelabs/risingwave · error · SinkError::Iceberg

failed to create iceberg table

Error message

failed to create iceberg table

What it means

This is the final step of table creation: catalog.create_table(&namespace, table_creation). Any failure returned by the catalog (namespace missing, permission denied, table already created concurrently, invalid location, storage errors) is wrapped into SinkError::Iceberg with the context 'failed to create iceberg table'.

Source

Thrown at src/connector/src/sink/iceberg/create_table.rs:268

            .location(location)
            .sort_order(sort_order)
            .build(),
        (Some(location), None, None) => table_creation_builder.location(location).build(),
        (None, Some(partition_spec), Some(sort_order)) => table_creation_builder
            .partition_spec(partition_spec)
            .sort_order(sort_order)
            .build(),
        (None, Some(partition_spec), None) => table_creation_builder
            .partition_spec(partition_spec)
            .build(),
        (None, None, Some(sort_order)) => table_creation_builder.sort_order(sort_order).build(),
        (None, None, None) => table_creation_builder.build(),
    };

    catalog
        .create_table(&namespace, table_creation)
        .await
        .map_err(|e| SinkError::Iceberg(anyhow!(e)))
        .context("failed to create iceberg table")?;
    Ok(true)
}

async fn create_namespace_if_not_exists(
    catalog: &dyn Catalog,
    namespace: &NamespaceIdent,
) -> Result<()> {
    let mut namespaces = vec![namespace.clone()];
    let mut parent = namespace.parent();
    while let Some(parent_namespace) = parent {
        parent = parent_namespace.parent();
        namespaces.push(parent_namespace);
    }

    for namespace in namespaces.into_iter().rev() {
        if !catalog
            .namespace_exists(&namespace)

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Inspect the chained underlying error for the catalog's response (auth, permission, location).
  2. Verify the table location's bucket/prefix exists and RisingWave's credentials can write to it.
  3. Confirm the namespace exists (create_namespace_if_not_exists ran successfully) and wasn't removed concurrently.
  4. Retry if the failure is transient; if the table was created concurrently, the existing table will be validated instead.

Example fix

// before: IAM role lacks s3:PutObject on the location
WITH (connector='iceberg', warehouse='s3://bucket/iceberg/', s3.access.key='...', ...)
// after: grant write permissions on the bucket/prefix or fix the access key
aws s3api put-object --bucket bucket --key iceberg/test --body /dev/null # verify write access first
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: verify write access to the target location and namespace existence
catalog.namespace_exists(&namespace).await?;
// and verify storage credentials, e.g.:
aws s3api put-object --bucket my-bucket --key iceberg/.write-test --body /dev/null

Try / catch

match catalog.create_table(&namespace, table_creation).await {
    Err(e) if is_retryable(&e) => retry_with_backoff(3, || create_table(...)),
    Err(e) => Err(SinkError::Iceberg(anyhow!(e)).context("failed to create iceberg table")),
    Ok(t) => Ok(t),
}

Prevention

When it happens

Trigger: create_table_if_not_exists_impl reaches catalog.create_table and the catalog client returns Err — e.g. the namespace does not exist and creation failed, the location bucket is not writable, credentials lack permission, or a concurrent process created the table between the table_exists check and create.

Common situations: Object storage credentials/permissions misconfigured; namespace was deleted between create_namespace_if_not_exists and create_table; REST catalog rejecting the request (quota, schema conflicts); transient catalog/storage outages.

Related errors


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