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
