Cliff Resnick
05/04/2026, 8:28 PMCREATE EXTERNAL CATALOG horizon
PROPERTIES (
"iceberg.catalog.uri" = "<https://my-account.snowflakecomputing.com/polaris/api/catalog>",
"type" = "iceberg",
"iceberg.catalog.type" = "rest",
"iceberg.catalog.warehouse" = "MY_DATABASE",
"iceberg.catalog.security" = "oauth2",
"iceberg.catalog.client.region" = "us-east-1",
"iceberg.catalog.oauth2.credential" = "eyJraWQiOi...",
"iceberg.catalog.oauth2.scope"='session:role:MY_SCOPED_ROLE',
"vended-credentials-enabled"="true"
);
I have successfully tested the credentials using curl to obtain an access token and use it to get table metadata. In StarRocks 4.0.8, I can show databases and it brings up a list of databases including MY_DATABASE. But when I try to run anything deeper, such as `show tables in <http://MY_DATABASE.MY|MY_DATABASE.MY>_SCHEMA I get errors in log saying client denied.Rocky
05/04/2026, 8:29 PMshow tables (while show databases works) usually occurs because Snowflake Horizon/Polaris requires nested namespace handling and specific access delegation settings that are not enabled by default in StarRocks.
Here are the specific configuration adjustments you should make:
1. Enable Nested Namespaces
Snowflake uses a hierarchical structure (Database -> Schema -> Table). By default, StarRocks might try to treat MY_DATABASE.MY_SCHEMA as a single-level namespace string. For Polaris-based catalogs like Horizon, you must explicitly enable nested namespace support:
sql
"iceberg.catalog.rest.nested-namespace-enabled" = "true"
2. Correct Property Names
In StarRocks, properties for the Iceberg REST catalog should consistently use the iceberg.catalog. prefix. In your snippet, vended-credentials-enabled was missing the prefix.
• Change "vended-credentials-enabled" = "true" to "iceberg.catalog.vended-credentials-enabled" = "true".
3. Add the Access Delegation Header
Snowflake Horizon often expects a specific header to explicitly request vended credentials (temporary S3/GCS keys). You can pass this via the rest.header property:
sql
"iceberg.catalog.rest.header.X-Iceberg-Access-Delegation" = "vended-credentials"
4. Verify Warehouse Name
For Snowflake Horizon, the iceberg.catalog.warehouse property must typically match your Snowflake Account Locator (e.g., ORG-ACCOUNT) or the specific Snowflake Database name, depending on your endpoint level. If show databases is showing the database name, ensure the warehouse matches the expected Polaris warehouse identifier.
Recommended Configuration Example
Try recreating your catalog with these refined properties:
sql
CREATE EXTERNAL CATALOG horizon
PROPERTIES (
"type" = "iceberg",
"iceberg.catalog.type" = "rest",
"iceberg.catalog.uri" = "https://<my-account>.<http://snowflakecomputing.com/polaris/api/catalog|snowflakecomputing.com/polaris/api/catalog>",
"iceberg.catalog.warehouse" = "MY_DATABASE", -- Ensure this is correct
"iceberg.catalog.security" = "oauth2",
"iceberg.catalog.oauth2.credential" = "eyJraWQiOi...", -- Your PAT
"iceberg.catalog.oauth2.scope" = "session:role:MY_SCOPED_ROLE",
-- Critical for Snowflake/Polaris
"iceberg.catalog.rest.nested-namespace-enabled" = "true",
"iceberg.catalog.vended-credentials-enabled" = "true",
"iceberg.catalog.rest.header.X-Iceberg-Access-Delegation" = "vended-credentials",
-- Storage Region
"aws.s3.region" = "us-east-1"
);
Why show databases worked but show tables failed?
• show databases: This calls the GET /v1/namespaces endpoint. This is a top-level call that often succeeds even if nested namespace support is off, as it returns the first level of the hierarchy.
• show tables: This calls GET /v1/namespaces/{ns}/tables. Without nested-namespace-enabled, StarRocks sends {ns} as a single string (e.g., MY_DATABASE.MY_SCHEMA). Snowflake expects a nested path (e.g., .../namespaces/MY_DATABASE/namespaces/MY_SCHEMA/tables). This mismatch or the missing delegation header often results in the "client denied" (403 Forbidden) response from Snowflake.
Note on Version: You mentioned StarRocks 4.0.8. While 4.0 is the upcoming major version focusing on "Catalog-Centric" security and improved vended credentials, if you are actually on a 3.4.x release, these properties still apply and are the standard way to fix REST connectivity issues with Polaris.
References
• data_source/catalog/iceberg/iceberg_rest_security.md
• data_source/catalog/iceberg/iceberg_catalog.mdCliff Resnick
05/04/2026, 8:57 PMRocky
05/04/2026, 8:57 PMiceberg.catalog.rest.nested-namespace-enabled is set to true, the engine often performs a recursive listing of all namespaces to resolve the hierarchy for a command like SHOW TABLES.
* The Problem: Snowflake Horizon's API can be slow to return deep recursive results, or StarRocks might be triggering multiple retries after internal 60-second timeouts.
* The 4.1 Improvement: StarRocks 4.1 introduces Optimized Metadata Caching and a more efficient lookup strategy for REST catalogs. Instead of broad recursive scans, it uses targeted namespace calls that significantly reduce the "time to first byte" for metadata operations.
2. Why "Client Denied" occurs
Even if your curl test worked, the StarRocks FE might be appending an incorrect suffix to the URI or using a different namespace path format when nested-namespace-enabled is active.
* Snowflake requires a very specific path: .../namespaces/DATABASE/namespaces/SCHEMA/tables.
* If the catalog property iceberg.catalog.warehouse is not set exactly to your Snowflake Account Locator (the one found in your URL, e.g., ORG-ACCOUNT), Snowflake may deny the request at the table level even if it allows the database-level listing.
3. Recommended Adjustments for 4.1
When you move to 4.1, use this refined configuration. Note the addition of the allowall access control property, which ensures StarRocks doesn't block queries before they even reach Snowflake:
sql
CREATE EXTERNAL CATALOG horizon
PROPERTIES (
"type" = "iceberg",
"iceberg.catalog.type" = "rest",
"iceberg.catalog.uri" = "https://<account>.<http://snowflakecomputing.com/polaris/api/catalog|snowflakecomputing.com/polaris/api/catalog>",
-- IMPORTANT: For Horizon, this should be your Snowflake Account Locator (e.g. MYORG-MYACCT)
"iceberg.catalog.warehouse" = "MY_DATABASE",
"iceberg.catalog.security" = "oauth2",
"iceberg.catalog.oauth2.credential" = "eyJraWQiOi...",
"iceberg.catalog.oauth2.scope" = "session:role:MY_SCOPED_ROLE",
-- Optimization properties in 4.1
"iceberg.catalog.rest.nested-namespace-enabled" = "true",
"iceberg.catalog.vended-credentials-enabled" = "true",
"catalog.access.control" = "allowall", -- Let Snowflake handle the AuthZ
-- Mandatory Header for Snowflake Vended Credentials
"iceberg.catalog.rest.header.X-Iceberg-Access-Delegation" = "vended-credentials"
);
Troubleshooting Steps
If you still see the 2.5-minute delay in 4.0.8 or 4.1:
1. Check FE Logs: Look at fe.log and search for RESTClient. You will see the exact URL StarRocks is calling. If the URL looks like .../namespaces/MY_DATABASE.MY_SCHEMA/tables (with a dot), then nested-namespace-enabled is not being respected correctly by that specific StarRocks build.
2. Verify Warehouse: Ensure the iceberg.catalog.warehouse property matches the "Warehouse" name defined in your Polaris/Horizon configuration. For Snowflake's internal catalog, this is usually the Snowflake Database name in uppercase.
3. Scope: Try setting "iceberg.catalog.oauth2.scope" = "PRINCIPAL_ROLE:ALL" if your custom role scope continues to return 403, just to rule out permission inheritance issues.
Conclusion: Moving to 4.1 is highly recommended. It was specifically hardened for "Catalog-Centric" workflows (like Snowflake Horizon) where the engine delegates security and relies heavily on vended credentials.
ReferencesRocky
05/04/2026, 8:57 PM