risingwavelabs/risingwave · error · iceberg::Error(ErrorKind::Unexpected)

Failed to check if table exists: {}

Error message

Failed to check if table exists: {}

What it means

table_exists checks for `{table_path}/metadata/version-hint.text` via file_io.exists. This error is thrown when that existence probe itself fails (as opposed to returning false), wrapping the underlying object-store error with the table context.

Source

Thrown at src/connector/src/connector_common/iceberg/storage_catalog.rs:363

    /// Drop a table from the catalog.
    async fn drop_table(&self, table: &TableIdent) -> iceberg::Result<()> {
        let table = self.load_table(table).await?;
        table
            .file_io()
            .delete_prefix(table.metadata().location())
            .await
    }

    async fn purge_table(&self, table: &TableIdent) -> iceberg::Result<()> {
        self.drop_table(table).await
    }

    /// Check if a table exists in the catalog.
    async fn table_exists(&self, table: &TableIdent) -> iceberg::Result<bool> {
        let table_path = self.table_path(table);
        let metadata_path = format!("{table_path}/metadata/version-hint.text");
        self.file_io.exists(&metadata_path).await.map_err(|err| {
            Error::new(
                ErrorKind::Unexpected,
                format!("Failed to check if table exists: {}", err.as_report()),
            )
        })
    }

    /// Rename a table in the catalog.
    async fn rename_table(&self, _src: &TableIdent, _dest: &TableIdent) -> iceberg::Result<()> {
        todo!()
    }

    /// Update a table to the catalog.
    async fn update_table(&self, mut commit: TableCommit) -> iceberg::Result<Table> {
        let table = self.load_table(commit.identifier()).await?;
        let requirements = commit.take_requirements();
        let updates = commit.take_updates();

        let metadata = table.metadata().clone();

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Read the wrapped cause (`{}` contains err.as_report()) and fix the root storage error it reports.
  2. Verify storage credentials, region, and endpoint configuration for the catalog.
  3. Grant the principal read/HEAD permission on the table's `metadata/` prefix.
  4. Confirm network reachability to the object store from the RisingWave/connector host.

Example fix

// before: IAM policy missing read access on metadata prefix
// after: allow HEAD/GET on table metadata
{"Effect":"Allow","Action":["s3:GetObject","s3:ListBucket"],"Resource":["arn:aws:s3:::bucket","arn:aws:s3:::bucket/db/table/*"]}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify storage config connectivity before catalog calls
let probe = file_io.exists(&format!("{warehouse}/probe")).await;
if probe.is_err() { return Err("object store credentials/endpoint invalid; fix config first"); }

Try / catch

match catalog.table_exists(&ident).await {
    Ok(exists) => exists,
    Err(e) => {
        log::error!("storage probe failed: {e}"); // inner report names the root cause
        return Err(anyhow!("fix object-store auth/endpoint, then retry: {e}"));
    }
}

Prevention

When it happens

Trigger: Any table_exists call where the storage backend errors on HEAD of the version-hint path: invalid or expired credentials, missing HeadObject/GetProperties permission, DNS/endpoint misconfiguration, storage service outage.

Common situations: Wrong S3 region or endpoint in catalog config; IAM policy lacking s3:ListBucket/GetObject on the metadata prefix; credentials not propagated to the connector; proxy/firewall blocking the object store.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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