databendlabs/databend · critical

not implemented: Not implemented for storage type

Error message

not implemented: Not implemented for storage type: {:?}

What it means

get_external_storage_connection in src/query/service/src/history_tables/external.rs builds connection info for a history table's external storage, but only S3-like, and Fs storage params are handled; any other StorageParams variant hits `unimplemented!("Not implemented for storage type: {:?}")` and panics during init.

Solutions

  1. Set the history-table external storage to S3-compatible or Fs storage in the config.
  2. Inspect the panicked message's storage type to see which variant leaked in, and fix the [storage] config section accordingly.
  3. If the target object store is Azure/GCS, use an S3-compatible endpoint or wait for/upgrade to a version supporting that type for history tables.
  4. For maintainers: replace unimplemented! with a config ErrorCode and validate the storage type at config parse time.

Example fix

// before
_type = "azure"  # used as history storage
// after (config)
[history.storage]
type = "s3"
bucket = "history-bucket"
...
Defensive patterns

Strategy: validation

Validate before calling

# pre-startup config check
if history_storage_type not in ("s3", "fs"):
    raise ConfigError(f"history storage type '{history_storage_type}' is not supported (use s3 or fs)")

Type guard

fn history_storage_supported(sp: &StorageParams) -> bool {
    matches!(sp, StorageParams::S3(_) | StorageParams::Fs(_) | StorageParams::S3WithSimdZip(_))
}

Try / catch

match get_external_storage_connection(&storage_params) {
    Ok(info) => info,
    Err(e) if e.to_string().contains("Not implemented for storage type") => {
        return Err(ErrorCode::InvalidConfig("history storage must be s3 or fs"));
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Configuring history tables' external storage with a StorageParams type other than S3-style or Fs — e.g. Azure/GCS/OBS/HDFS-style storage params — so the catch-all `_` arm is reached at startup/init.

Common situations: A deployment reuses the main query storage config (set to Azure Blob or GCS) for history-table export, or a typo/misconfiguration yields an unexpected StorageParams variant; the node panics during initialization.

Related errors


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/493bf78222a55a0e. Report an issue: GitHub.

Appendix: source

Thrown at src/query/service/src/history_tables/external.rs:194

        }
        StorageParams::Obs(config) => {
            info.set_uri(
                Scheme::Obs.to_string(),
                config.bucket.clone(),
                config.root.clone(),
            );

            info.set_value("endpoint_url".to_string(), config.endpoint_url.clone());
            info.set_value("access_key_id".to_string(), config.access_key_id.clone());
            info.set_value(
                "secret_access_key".to_string(),
                config.secret_access_key.clone(),
            );
        }
        StorageParams::Fs(config) => {
            info.uri = format!("file://{}", normalize_root(&config.root));
        }
        _ => unimplemented!("Not implemented for storage type: {:?}", storage_params),
    }
    info
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_to_create_stage_sql() {
        let mut connection = ExternalStorageConnection::new(BTreeMap::new());
        connection.set_uri(
            "s3".to_string(),
            "test-bucket".to_string(),
            "test".to_string(),
        );
        connection.set_value("access_key_id".to_string(), "test_key".to_string());

View on GitHub (pinned to 288d84d76e)