risingwavelabs/risingwave · error · anyhow::Error

Invalid iceberg table identifier

Error message

Invalid iceberg table identifier '{}': identifier parts must not be empty

What it means

The Iceberg table identifier built from `database_name` and `table_name` with-properties produced an empty part after splitting on '.'. The connector refuses identifiers whose namespace or table segment is empty because Iceberg catalogs require non-empty identifier components. `full_identifier()` echoes the offending value so the developer can see what was parsed.

Solutions

  1. Set a non-empty `table.name` property with no leading/trailing/embedded dots.
  2. If `database.name` is supplied, ensure it is non-empty and each dot-separated segment is non-empty.
  3. Check upstream variable substitution or SQL generation that may inject an empty value.

Example fix

// before
create table t with (
  connector = 'iceberg',
  database.name = 'db.',
  table.name = 'events'
);
// after
create table t with (
  connector = 'iceberg',
  database.name = 'db',
  table.name = 'events'
);
Defensive patterns

Strategy: validation

Validate before calling

function validateIcebergIdentifier(db, table) {
  const parts = [...(db ?? '').split('.'), ...table.split('.')];
  if (parts.some(p => p.length === 0)) {
    throw new Error(`Invalid iceberg identifier: ${db ? db + '.' : ''}${table}`);
  }
}

Type guard

const isValidIdentifier = (s) => typeof s === 'string' && s.split('.').every(p => p.length > 0);

Prevention

When it happens

Trigger: Calling `identifier_parts` (via `to_table_ident` or `validate`) with `table_name` set to "", starting/ending with '.', containing consecutive dots, or a `database_name` that is empty or has empty segments (e.g. "a..b", ".tbl", "db.").

Common situations: Users writing `create table ... with (table.name = '')` or `database.name = 'db.'`; template/variable interpolation leaving a placeholder empty; copy-paste of dotted identifiers from another system with trailing separators.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at src/connector/src/connector_common/iceberg/mod.rs:270

impl IcebergTableIdentifier {
    pub fn database_name(&self) -> Option<&str> {
        self.database_name.as_deref()
    }

    pub fn table_name(&self) -> &str {
        &self.table_name
    }

    fn identifier_parts(&self) -> ConnectorResult<Vec<&str>> {
        let mut parts = Vec::new();
        if let Some(database_name) = &self.database_name {
            parts.extend(database_name.split('.'));
        }
        parts.extend(self.table_name.split('.'));

        if parts.iter().any(|part| part.is_empty()) {
            bail!(
                "Invalid iceberg table identifier '{}': identifier parts must not be empty",
                self.full_identifier()
            );
        }

        Ok(parts)
    }

    fn full_identifier(&self) -> String {
        match &self.database_name {
            Some(database_name) => format!("{}.{}", database_name, self.table_name),
            None => self.table_name.clone(),
        }
    }

    pub fn to_table_ident(&self) -> ConnectorResult<TableIdent> {
        let ret = TableIdent::from_strs(self.identifier_parts()?);

View on GitHub (pinned to 6469eb736d)