Skip to content

feat: actually using namespace error variants#6275

Merged
wjones127 merged 10 commits intolance-format:mainfrom
hamersaw:chore/use-namespace-error-variants
Mar 26, 2026
Merged

feat: actually using namespace error variants#6275
wjones127 merged 10 commits intolance-format:mainfrom
hamersaw:chore/use-namespace-error-variants

Conversation

@hamersaw
Copy link
Copy Markdown
Contributor

@hamersaw hamersaw commented Mar 24, 2026

In the rust SDK we have a NamespaceError that contains a message and an error code. Additionally, in both the Java and python SDKs we have logic to parse this type (and error codes) to produce native Java exceptions. The problem, is that in the namespace-impls we are never using them. Therefore the rust NamespaceError type is never used and the Java / python SDK conversion code the parse and throw native errors is essentially dead code. In this PR, we update the namespace-impls to actually throw the correct error types.

Closes #6240

@github-actions github-actions Bot added the chore label Mar 24, 2026
@github-actions
Copy link
Copy Markdown
Contributor

PR Review

Clean, mechanical migration from generic Error::namespace_source to typed NamespaceError variants. The error categorization choices look correct overall. Two issues worth addressing:

P1: REST client maps all HTTP errors to NamespaceError::Internal

In rest.rs, every non-success HTTP response is now mapped to NamespaceError::Internal. This defeats the purpose of this PR — if the REST server returns a structured error with an error code (e.g., 404 → TableNotFound, 409 → TableAlreadyExists), the client-side code should try to parse and preserve that code rather than collapsing everything to Internal. The Java/Python SDK parsing logic you mention in the description would need the correct error codes to come through.

Consider either:

  1. Parsing the response body for a structured error (if the REST API returns error codes), or
  2. At minimum, mapping HTTP status codes to appropriate variants (404 → TableNotFound/NamespaceNotFound, 409 → TableAlreadyExists/ConcurrentModification, 400 → InvalidInput, 403 → PermissionDenied, 401 → Unauthenticated, 503 → ServiceUnavailable).

If this is intentionally deferred, a TODO comment would be helpful.

Minor: Verbose lance_core::Error::from(NamespaceError::... { ... }) pattern in .map_err

Several .map_err closures use the explicit lance_core::Error::from(NamespaceError::Foo { message: ... }) form, while others use the more concise NamespaceError::Foo { ... }.into(). Both work, but the inconsistency is noticeable. The .into() form is shorter — consider standardizing on it throughout.


Tests are updated to match the new error messages. The variant choices (TableNotFound, InvalidInput, NamespaceAlreadyExists, ConcurrentModification, etc.) all look semantically appropriate. LGTM otherwise.

@hamersaw
Copy link
Copy Markdown
Contributor Author

Mentioning parallel work that updates to throw on TableNodeFound - #6267

@hamersaw
Copy link
Copy Markdown
Contributor Author

Another effort to add TableNotFound - #6252

hamersaw and others added 2 commits March 24, 2026 09:58
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace generic lance_core::Error variants (invalid_input_source,
io_source, not_supported_source, etc.) with NamespaceError variants
throughout the namespace-impls crate. This ensures errors flow through
the LanceError::Namespace path and get properly converted to
lance_namespace.errors Python exceptions with correct error codes.

Also fix table_exists fallback to only fall through to directory
check for single-level IDs, matching the existing describe_table
pattern.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@jackye1995 jackye1995 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, long overdue. I think the title should be feat or fix, not chore since it changes user experience.

@hamersaw hamersaw changed the title chore: actually using namespace error variants feat: actually using namespace error variants Mar 25, 2026
@github-actions github-actions Bot added the enhancement New feature or request label Mar 25, 2026
Copy link
Copy Markdown
Contributor

@wjones127 wjones127 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems good, but I'm noting there is a pre-existing issue where the NamespaceError has Display implementations and message fields. Most of the time, they seem to duplicate information. I've noted two cases of this, but here are several more. I'd consider cleaning those up, either here or in a follow up.

Comment on lines +2127 to +2130
None => Err(NamespaceError::NamespaceNotFound {
message: format!("Namespace '{}' not found", object_id),
}
.into()),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: This message duplicates what is in the Display implementation for this error:

/// The specified namespace does not exist.
#[snafu(display("Namespace not found: {message}"))]
NamespaceNotFound { message: String },

The error will print as:

Namespace not found: Namespace '{name}' not found

Consider just putting the quoted object id as the message:

Suggested change
None => Err(NamespaceError::NamespaceNotFound {
message: format!("Namespace '{}' not found", object_id),
}
.into()),
Err(NamespaceError::NamespaceNotFound {
message: format!("'{}'", object_id)
}
.into())

Then the message would be like:

Namespace not found: '{name}'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also change the error itself to table a table name instead of a custom message.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great call out. I updated all of these that I could find. But just like replacing all the errors, I'm sure I missed one and will have to come back and fix it 😆

Comment on lines +2160 to +2163
return Err(NamespaceError::NamespaceAlreadyExists {
message: format!("Namespace '{}' already exists", object_id),
}
.into());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue(non-blocking): similar problem here: message duplicates the Display implementations of NamespaceError::NamespaceAlreadyExists:

/// A namespace with this name already exists.
#[snafu(display("Namespace already exists: {message}"))]
NamespaceAlreadyExists { message: String },

hamersaw and others added 3 commits March 25, 2026 15:24
The Display impl on NamespaceError variants already adds context like
"Namespace not found: " or "Table already exists: ", so messages should
contain just the entity identifier rather than repeating the variant
semantics (e.g. "Namespace 'foo' not found").

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The REST server was serializing ns_err.to_string() (which includes the
Display prefix) as the error message. The client then wrapped that full
string back into a new NamespaceError, causing doubled prefixes like
"Namespace not empty: Namespace not empty: ...". Use the new message()
accessor to send just the inner message without the Display prefix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@wjones127 wjones127 merged commit 3a82648 into lance-format:main Mar 26, 2026
28 checks passed
@hamersaw hamersaw deleted the chore/use-namespace-error-variants branch March 26, 2026 16:49
wjones127 pushed a commit to wjones127/lance that referenced this pull request Mar 29, 2026
In the rust SDK we have a `NamespaceError` that contains a message and
an error code. Additionally, in both the Java and python SDKs we have
logic to parse this type (and error codes) to produce native Java
exceptions. The problem, is that in the `namespace-impls` we are never
using them. Therefore the rust `NamespaceError` type is never used and
the Java / python SDK conversion code the parse and throw native errors
is essentially dead code. In this PR, we update the `namespace-impls` to
actually throw the correct error types.

Closes lance-format#6240

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

namespace_exists() / table_exists() throw RuntimeError instead of NamespaceNotFoundError / TableNotFoundError

3 participants