FANNG1 opened a new issue, #12468:
URL: https://github.com/apache/gravitino/issues/12468
### Version
main branch
Verified on `main` @ `58e0e17a9`, and reproduced against a deployed 1.3.0
server.
### Describe what's wrong
`ListNamespaces` on the Lance REST service returns a successful, empty
response for **any** two-level identifier, without checking that the identifier
refers to anything that exists.
`GravitinoLanceNameSpaceOperations.listNamespaces` short-circuits the
deepest level:
```java
//
lance/lance-common/src/main/java/org/apache/gravitino/lance/common/ops/gravitino/GravitinoLanceNameSpaceOperations.java
switch (nsId.levels()) {
case 0:
namespaces = Arrays.stream(namespaceWrapper.listCatalogsInfo())
.filter(namespaceWrapper::isLakehouseCatalog)
.map(Catalog::name).collect(Collectors.toList());
break;
case 1:
Catalog catalog =
namespaceWrapper.loadAndValidateLakehouseCatalog(nsId.levelAtListPos(0));
namespaces = Lists.newArrayList(namespaceWrapper.listSchemas(catalog));
break;
case 2:
namespaces = Lists.newArrayList(); // <-- returns empty without
validating anything
break;
```
Returning an empty list at level 2 is correct — a schema has no child
namespaces, only tables. The bug is that it never validates the catalog or the
schema first, so a nonexistent path is reported as an existing-but-empty
namespace.
This produces a self-contradictory result: **a two-level identifier succeeds
while its own one-level prefix fails.**
```
GET /lance/v1/namespace/BOGUS_CATALOG%24BOGUS_SCHEMA/list?delimiter=%24
{"namespaces":[]} <-- success
GET /lance/v1/namespace/BOGUS_CATALOG/list?delimiter=%24
{"error":"Catalog not found: BOGUS_CATALOG", ...} <-- correctly fails
```
`listNamespaces` is also the **only** namespace operation that behaves this
way. Every sibling validates at level 2:
| Operation | Level-2 behaviour on a nonexistent schema |
|---|---|
| `describeNamespace` | `loadAndValidateLakehouseCatalog` + `loadSchema` →
`NoSuchSchemaException` |
| `namespaceExists` | `loadAndValidateLakehouseCatalog` + `schemaExists` →
`NamespaceNotFoundException` |
| `dropNamespace` | delegates to `dropSchema` → validates |
| `createNamespace` | delegates to `createOrUpdateSchema` → validates |
| **`listNamespaces`** | **returns `{"namespaces":[]}`** |
Since the level-1 branch already resolves the catalog with
`loadAndValidateLakehouseCatalog`, the level-2 branch skipping it looks like an
oversight rather than a deliberate choice.
#### Why it matters
`ListNamespaces` is the natural operation for a client to validate a
configured namespace path — it is cheap, read-only, and available at every
depth. A client that points its configuration at a mistyped schema gets a clean
success back and only discovers the mistake much later, on the first query.
Concretely: Apache Doris's Lance REST catalog takes a
`lance.namespace.parent` property and probes it at catalog-creation time. When
that parent is two levels deep (`<catalog>$<schema>` — the configuration that
maps a Doris database onto a Gravitino schema), a typo in the schema name
passes catalog creation silently. The catalog is created, `SHOW DATABASES`
returns a single empty entry, and the error only surfaces when someone tries to
read.
### Error message and/or stacktrace
There is no error — that is the bug. The request returns HTTP 200 with an
empty namespace list:
```console
$ curl -s
'http://127.0.0.1:9101/lance/v1/namespace/BOGUS_CATALOG%24BOGUS_SCHEMA/list?delimiter=%24'
{"namespaces":[]}
```
For contrast, the sibling operations on the same nonexistent path do report
the problem:
```console
$ curl -s -X POST
'http://127.0.0.1:9101/lance/v1/namespace/lance_catalog%24BOGUS_SCHEMA/exists?delimiter=%24'
\
-H 'Content-Type: application/json' -d '{}'
{"error":"Schema not found: BOGUS_SCHEMA","code":1, ...}
$ curl -s -X POST
'http://127.0.0.1:9101/lance/v1/namespace/lance_catalog%24BOGUS_SCHEMA/describe?delimiter=%24'
\
-H 'Content-Type: application/json' -d '{}'
{"error":"Failed to operate schema(s) [BOGUS_SCHEMA] operation [LOAD] under
catalog [lance_catalog],
reason [Schema test.lance_catalog.BOGUS_SCHEMA does not exist]", ...}
```
### How to reproduce
Gravitino 1.3.0 or `main`, with the Lance REST service enabled as an
auxiliary service:
```properties
# conf/gravitino.conf
gravitino.auxService.names = lance-rest
gravitino.lance-rest.classpath = lance-rest-server/libs
gravitino.lance-rest.httpPort = 9101
gravitino.lance-rest.namespace-backend = gravitino
gravitino.lance-rest.gravitino-uri = http://127.0.0.1:8090
gravitino.lance-rest.gravitino-metalake = test
```
Any `lakehouse-generic` catalog will do; no schema or table needs to exist.
```bash
# 1. fully fabricated two-level identifier -> succeeds
curl -s
'http://127.0.0.1:9101/lance/v1/namespace/BOGUS_CATALOG%24BOGUS_SCHEMA/list?delimiter=%24'
# {"namespaces":[]}
# 2. its own one-level prefix -> correctly fails
curl -s
'http://127.0.0.1:9101/lance/v1/namespace/BOGUS_CATALOG/list?delimiter=%24'
# {"error":"Catalog not found: BOGUS_CATALOG", ...}
# 3. real catalog, fabricated schema -> still succeeds
curl -s
'http://127.0.0.1:9101/lance/v1/namespace/<real_catalog>%24BOGUS_SCHEMA/list?delimiter=%24'
# {"namespaces":[]}
```
Step 1 succeeding while step 2 fails is the clearest statement of the bug:
the child of a nonexistent parent is reported to exist.
### Additional context
Suggested fix — validate before returning the empty list, reusing the
helpers the sibling operations already use:
```java
case 2:
Catalog parent =
namespaceWrapper.loadAndValidateLakehouseCatalog(nsId.levelAtListPos(0));
String schemaName = nsId.levelAtListPos(1);
if (!namespaceWrapper.schemaExists(parent, schemaName)) {
throw new NamespaceNotFoundException(
"Schema not found: " + schemaName,
CommonUtil.formatCurrentStackTrace(), schemaName);
}
namespaces = Lists.newArrayList();
break;
```
This costs one metadata lookup on a path that is currently a no-op, and
makes `listNamespaces` consistent with `namespaceExists`, which already raises
exactly this exception for exactly this case.
Worth checking whether `ListTables` has the mirror-image gap at other depths
while someone is in this code.
Found while testing Apache Doris's Lance REST catalog against Gravitino —
apache/doris#66772 covers the Doris-side findings from that run. This issue is
independent of that work and reproducible with `curl` alone.
Related: #8889 (EPIC: add Lance REST Service supports).
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]