risingwavelabs/risingwave · error · iceberg::Error(ErrorKind::Unexpected)
Fail to check exist
Error message
Fail to check exist
What it means
After writing the new metadata file, commit_table must rewrite `version-hint.text`. Before overwriting it calls file_io.exists; if that existence check itself fails (I/O, auth, network), this error wraps the failure because the catalog cannot safely proceed to delete/rewrite the hint.
Source
Thrown at src/connector/src/connector_common/iceberg/storage_catalog.rs:217
// # NOTE
// Iceberg rust didn't support rename operation now, so this commit operation is not atomic.
let final_metadata_file_path = format!(
"{table_path}/metadata/v{}.metadata.json",
current_version + 1
);
self.file_io()
.new_output(final_metadata_file_path)?
.write(serde_json::to_string(&next_metadata)?.into())
.await?;
// write version hint
let final_file_path = format!("{table_path}/metadata/version-hint.text");
if self
.file_io()
.exists(final_file_path.as_str())
.await
.map_err(|_| Error::new(ErrorKind::Unexpected, "Fail to check exist"))?
{
self.file_io().delete(final_file_path.as_str()).await?;
}
self.file_io()
.new_output(final_file_path)?
.write(format!("{}", current_version + 1).into())
.await?;
Ok(())
}
}
#[async_trait]
impl Catalog for StorageCatalog {
/// List namespaces from table.
async fn list_namespaces(
&self,
_parent: Option<&NamespaceIdent>,View on GitHub (pinned to 6469eb736d)
Solutions
- Check the underlying cause in the chained error source (the wrapped error is discarded here, so enable file_io/opendal logging to see the root cause).
- Verify storage credentials and that the principal has read (HEAD) permission on the table's metadata path.
- Test connectivity to the object store endpoint (network, DNS, region config).
- Retry the commit after transient storage errors are resolved.
Defensive patterns
Strategy: retry
Validate before calling
// preflight storage access before committing
file_io.exists(&format!("{table_path}/metadata/version-hint.text")).await
.expect("object store unreachable or unauthorized; fix credentials/endpoint before commit"); Try / catch
// bounded retry for transient storage failures
for attempt in 0..3 {
match catalog.commit_table(path, metadata.clone()).await {
Err(e) if e.to_string().contains("Fail to check exist") && attempt < 2 => {
tokio::time::sleep(Duration::from_secs(1 << attempt)).await;
continue;
}
other => break other,
}
} Prevention
- Use long-lived or auto-rotated credentials that outlast long jobs
- Grant HEAD/read permissions on the table metadata prefix
- Monitor object-store health and endpoint/region configuration
When it happens
Trigger: Calling update_table where the storage backend returns an error on HEAD/stat of `{table_path}/metadata/version-hint.text`: expired or missing credentials, transient network failure, bucket/permission changes mid-operation.
Common situations: S3/GCS/Azure credentials rotated or revoked during a long job; bucket policy change removing HeadObject permission; region/endpoint misconfiguration; object-store outage.
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
- check if version hint exist failed: {}
- Failed to check if table exists: {}
- (dataset guard acquisition error)
- disk error: {msg}
- ObjectStore failed with IO error: {0}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/3a9303f833992a76.
Report an issue: GitHub.