Hi Yufei

I fully agree the current property name is confusing.
I believe the problem is worse than a naming issue :)

I think, whether tables follow namespace nesting, is governed by
ALLOW_UNSTRUCTURED_TABLE_LOCATION, not by
ALLOW_NAMESPACE_CUSTOM_LOCATION. So your proposal wouldn't actually
constraint table layout. That said, the underlying concern still holds
one level up: mapping a namespace onto a pre-existing bucket layout
that doesn't mirror the name hierarchy is a legitimate non-test use
case, and your #2 would forbit it (which is good).

I think the flag's "false" path (by default) appears to be broken in
two independent ways:

1. Namespace creation fails with the default config.
validateNamespaceLocation builds the expected location set from the
storage config's allowed-locations, while the actual default location
resolves from the catalog's default-base-location. Those two are only
required to be in a parent/child relationship, and
default-base-location is merged into allowed-locations only when the
user supplies none. So with allowed-locations=[s3://bucket/foo] and
default-base-location=s3://bucket/foo/my-catalog, creating a namespace
with no location property at all is rejected (with something like
"Expected a location in: [s3://bucket/foo/ns/] Got location:
s3://bucket/foo/my-catalog/ns/).

2. updateNamespaceProperties carrying "location" always fails. The
namespace compared against itself, producting something like "Expected
location: [<loc>/ns/ns/]", and the new value is never validated at
all.

I think this explains why every test profile, the regtests compose
file and both Spark getting-started compose files set
ALLOW_NAMESPACE_CUSTOM_LOCATION=true (not because they want arbitrary
locations, but because "false" is unusable :) ). That also means we
have much less real-world reliance on the current "true" semantics.

I suggest we separate the two conversations. What we discuss here are
real bugs and we should fix it (not necessarily renaming).

On semantics, my view is that the invariant worth enforcing is the
storage boundary, not the name hierarchy. Staying inside the ancestor
storage config's allowed-locations is the acutal tenancy bounday and
it's what we enforce everywhere else. Nesting under the parent
namespace's location is a layout convention: useful as a default,
wrong as a hard rule, for exactly the reason Dmitri gives.
It's worth noting the current "true" path checks neither: you can
create a namespace at s3://someone-else-bucket/ and it succeeds, it's
just permanently unusable, since table creation later fails against
the catalog's allowed-locations. No credential-vending exposure
(LocationRestrictions only ever sources allowed-locations from the
storage-config entity, so the flag's description is accurate there),
but it's a bad failure mode.

So rather than flipping the boolean or adding a second one, I propose
we replace it with a three-valued setting:
- DEFAULT_ONLY: location must be the canonical parent/name (today's
"false", fixed so it actually resolves against default-base-location.
- UNDER_PARENT: any caller specified location under the parent's
location (corresponding to your proposal: the state the current name
implies but which has never existed).
- ALLOWED: any location within the ancestor storage config's
allowed-locations (todat's "true", plus the missing check).

Truly arbitrary locations outside allowed-locations would no longer be
reachable, which I don't think we lose anything by dropping.

My reason for preferring an enum over another boolean is because this
config space already has ALLOW_NAMESPACE_LOCATION_OVERLAP,
ALLOW_UNSTRUCTURED_TABLE_LOCATION, ALLOW_TABLE_LOCATION_OVERLAP,
DEFAULT_LOCATION_OBJECT_STORAGE_PREFIX_ENABLED and
OPTIMIZED_SIBLING_CHECK (wow, we are pretty inventive :) ), and we
already had to add a runtime guard (that tells the operators "this is
not a safe combination of configurations"). Adding a fourth boolean
makes that even worse :)

Abour your question (#2): I don't know of non-test users of arbitrary
locations, I expect most deployements are on "true" simply to make
namespace creation work (so they are likely relying on UNDER_PARENT or
ALLOWED semantics, not on arbitrary placement).

The table-level equivalent of "must be under the parent" is
ALLOW_UNSTRUCTURED_TABLE_LOCATION. Whatever we decide, it would be
good to name the namespace level knob symmetrically, since it's the
same concept one level up.

Regards
JB

On Mon, Aug 31, 2026 at 2:26 PM Yufei Gu <[email protected]> wrote:
>
> Hi folks,
>
> I’d like to clarify the intended behavior of
> ALLOW_NAMESPACE_CUSTOM_LOCATION.
>
> Today, when it's true, Polaris skips parent-location validation, so a
> namespace can be created anywhere, not just at a custom location under its
> parent. The name does not make this “arbitrary location” behavior obvious,
> which is confusing. Users may consider different cases, such as creating a
> custom location under the parent. Most repository uses appear to be for
> tests, though the setting is externally configurable and downstream users
> may rely on it.
>
> I think the more useful behavior would be to allow caller-specified
> locations while keeping them within the parent’s storage boundary:
>
>    1. Top-level namespaces must stay within the catalog’s default base
>    location.
>    2. Nested namespaces must stay within their parent namespace.
>    3. Existing overlap checks still apply.
>
> Changing the flag’s behavior could break use cases relying on locations
> outside the parent, but I'm less concerned as it's mainly used for tests
> now. I'd still like feedback on these points:
>
>    1. Should we change the existing flag or introduce a new
>    constrained-location setting?
>    2. Are there known non-test use cases for completely arbitrary namespace
>    locations?
>
> Yufei

Reply via email to