Skip to content

feat: Add catchableByTry flag to ErrorCode for extensible TRY error handling#26949

Merged
feilong-liu merged 1 commit intoprestodb:masterfrom
pradeepvaka:user/pvaka/tryexcpy
Jan 16, 2026
Merged

feat: Add catchableByTry flag to ErrorCode for extensible TRY error handling#26949
feilong-liu merged 1 commit intoprestodb:masterfrom
pradeepvaka:user/pvaka/tryexcpy

Conversation

@pradeepvaka
Copy link
Copy Markdown
Contributor

@pradeepvaka pradeepvaka commented Jan 12, 2026

Add a catchableByTry boolean flag to ErrorCode that allows errors to be declaratively marked as catchable by the TRY() function. This replaces hardcoded error code checks in TryFunction with a single flag check, making it extensible for future error types.

Changes:

  • Add catchableByTry field to ErrorCode with JSON/Thrift serialization
  • Mark existing TRY-catchable errors in StandardErrorCode: DIVISION_BY_ZERO, INVALID_CAST_ARGUMENT, INVALID_FUNCTION_ARGUMENT, NUMERIC_VALUE_OUT_OF_RANGE
  • Mark all RestErrorCode errors as catchableByTry to handle remote function failures gracefully (REST_SERVER_ERROR, REST_SERVER_TIMEOUT, REST_SERVER_CONNECT_ERROR, etc.)
  • Simplify TryFunction.propagateIfUnhandled() to use isCatchableByTry()

This allows any future error code to be marked as TRY-catchable at definition time without modifying TryFunction.

== NO RELEASE NOTE ==

@pradeepvaka pradeepvaka requested review from a team and elharo as code owners January 12, 2026 23:03
@prestodb-ci prestodb-ci added the from:Meta PR from Meta label Jan 12, 2026
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Jan 12, 2026

Reviewer's Guide

Introduces a new catchableByTry flag on ErrorCode (including JSON/Thrift serialization) and wires it through StandardErrorCode, TryFunction, and RestErrorCode so TRY() catch behavior is driven by an error-code property instead of hardcoded checks, while marking the relevant standard and REST errors as TRY‑catchable.

Sequence diagram for TRY function using catchableByTry-based error handling

sequenceDiagram
  actor User
  participant QueryEngine
  participant TryFunction
  participant Supplier as UserExpressionSupplier
  participant RemoteFunction
  participant RestNamespaceManager
  participant PrestoException
  participant ErrorCode

  User->>QueryEngine: Submit query with TRY(remote_function_call(...))
  QueryEngine->>TryFunction: evaluate(supplier, defaultValue)
  TryFunction->>Supplier: get()
  Supplier->>RemoteFunction: invoke()
  RemoteFunction->>RestNamespaceManager: HTTP request
  RestNamespaceManager-->>RemoteFunction: REST_SERVER_ERROR (ErrorCode catchableByTry = true)
  RemoteFunction-->>Supplier: throws PrestoException
  Supplier-->>TryFunction: throws PrestoException

  TryFunction->>PrestoException: catch
  TryFunction->>ErrorCode: getErrorCode()
  TryFunction->>ErrorCode: isCatchableByTry()
  alt error is catchableByTry == true
    TryFunction-->>QueryEngine: return defaultValue (TRY swallows error)
    QueryEngine-->>User: query continues, TRY result = defaultValue
  else error is catchableByTry == false
    TryFunction-->>QueryEngine: rethrow PrestoException
    QueryEngine-->>User: query fails with error
  end
Loading

Class diagram for updated error handling with catchableByTry flag

classDiagram

class ErrorCode {
  -int code
  -String name
  -ErrorType type
  -boolean retriable
  -boolean catchableByTry
  +ErrorCode(int code, String name, ErrorType type, boolean retriable, boolean catchableByTry)
  +ErrorCode(int code, String name, ErrorType type)
  +ErrorCode(int code, String name, ErrorType type, boolean retriable)
  +int getCode()
  +String getName()
  +ErrorType getType()
  +boolean isRetriable()
  +boolean isCatchableByTry()
  +String toString()
}

class StandardErrorCode {
  <<enum>>
  -ErrorCode errorCode
  +StandardErrorCode(int code, ErrorType type)
  +StandardErrorCode(int code, ErrorType type, boolean retriable)
  +StandardErrorCode(int code, ErrorType type, boolean retriable, boolean catchableByTry)
  +ErrorCode toErrorCode()
}

class RestErrorCode {
  <<enum>>
  -ErrorCode errorCode
  +RestErrorCode(int code, ErrorType type)
  +ErrorCode toErrorCode()
}

class TryFunction {
  +static <T> T evaluate(Supplier~T~ supplier, T defaultValue)
  -static void propagateIfUnhandled(PrestoException e)
}

class PrestoException {
  +ErrorCode getErrorCode()
}

class ErrorType

StandardErrorCode --> ErrorCode : wraps
RestErrorCode --> ErrorCode : wraps
PrestoException --> ErrorCode : uses
TryFunction --> PrestoException : catches
TryFunction --> ErrorCode : checks isCatchableByTry

%% Highlight specific enum constants that now set catchableByTry
class StandardErrorCode_InvalidFunctionArgument as StandardErrorCode_INVALID_FUNCTION_ARGUMENT {
}
class StandardErrorCode_DivisionByZero as StandardErrorCode_DIVISION_BY_ZERO {
}
class StandardErrorCode_InvalidCastArgument as StandardErrorCode_INVALID_CAST_ARGUMENT {
}
class StandardErrorCode_NumericValueOutOfRange as StandardErrorCode_NUMERIC_VALUE_OUT_OF_RANGE {
}

StandardErrorCode_INVALID_FUNCTION_ARGUMENT ..> ErrorCode : catchableByTry = true
StandardErrorCode_DIVISION_BY_ZERO ..> ErrorCode : catchableByTry = true
StandardErrorCode_INVALID_CAST_ARGUMENT ..> ErrorCode : catchableByTry = true
StandardErrorCode_NUMERIC_VALUE_OUT_OF_RANGE ..> ErrorCode : catchableByTry = true

RestErrorCode ..> ErrorCode : catchableByTry = true
Loading

File-Level Changes

Change Details Files
Add catchableByTry metadata to ErrorCode and wire it through constructors and serialization.
  • Extend ErrorCode with a catchableByTry boolean field stored alongside existing metadata.
  • Update the JSON/Thrift constructor to accept catchableByTry and validate/store it.
  • Provide new overloaded ErrorCode constructors so existing call sites default catchableByTry to false.
  • Expose isCatchableByTry() with JSON and Thrift annotations so it participates in serialization.
presto-common/src/main/java/com/facebook/presto/common/ErrorCode.java
Mark selected standard error codes as TRY-catchable and extend StandardErrorCode enum constructors to support the new flag.
  • Flag INVALID_FUNCTION_ARGUMENT, DIVISION_BY_ZERO, INVALID_CAST_ARGUMENT, and NUMERIC_VALUE_OUT_OF_RANGE as catchableByTry while keeping them non-retriable.
  • Change StandardErrorCode constructor chaining to carry the catchableByTry flag through to the underlying ErrorCode instance.
  • Ensure default StandardErrorCode constructors still initialize catchableByTry to false for all other error codes.
presto-spi/src/main/java/com/facebook/presto/spi/StandardErrorCode.java
Refactor TryFunction to use the new catchableByTry flag instead of hardcoded error-code checks.
  • Replace the explicit list of TRY-catchable error codes in propagateIfUnhandled() with a single isCatchableByTry() check on the exception’s ErrorCode.
  • Rely on error-code metadata to decide whether TRY should swallow or rethrow an error, making future extensions declarative.
presto-main-base/src/main/java/com/facebook/presto/operator/scalar/TryFunction.java
Make all REST function-namespace errors TRY-catchable for graceful handling of remote failures.
  • Change RestErrorCode to construct underlying ErrorCode instances with catchableByTry set to true while keeping retriable false.
  • Document intent that all REST errors are handled by TRY to avoid query failures on remote function errors.
presto-function-namespace-managers/src/main/java/com/facebook/presto/functionNamespace/rest/RestErrorCode.java

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `presto-main-base/src/main/java/com/facebook/presto/operator/scalar/TryFunction.java:161` </location>
<code_context>
-                || errorCode == INVALID_CAST_ARGUMENT.toErrorCode().getCode()
-                || errorCode == INVALID_FUNCTION_ARGUMENT.toErrorCode().getCode()
-                || errorCode == NUMERIC_VALUE_OUT_OF_RANGE.toErrorCode().getCode()) {
+        if (e.getErrorCode().isCatchableByTry()) {
             return;
         }
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Re-evaluate whether TRY should rely solely on `isCatchableByTry` without also checking error type.

Previously, TRY only swallowed a few explicitly whitelisted USER_ERROR codes. With this change, any `PrestoException` whose `ErrorCode` is marked `catchableByTry` will be ignored, including INTERNAL/EXTERNAL errors, which could mask serious issues if a code is misclassified.

Consider constraining this to USER errors (e.g., `e.getErrorCode().getType() == USER_ERROR && e.getErrorCode().isCatchableByTry()`) or clearly enforcing/documenting that only safe USER_ERROR codes can ever be marked `catchableByTry`.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

…TRY error handling

This change adds a `catchableByTry` boolean field to ErrorCode that indicates
whether an error can be caught by the TRY() SQL function. This makes TRY error
handling extensible without requiring code changes to TryFunction.java.

Changes:
- Add `catchableByTry` field to ErrorCode.java with @ThriftField(5) and @JsonProperty
- Add backward-compatible constructors that default catchableByTry to false
- Mark DIVISION_BY_ZERO, INVALID_CAST_ARGUMENT, INVALID_FUNCTION_ARGUMENT,
  and NUMERIC_VALUE_OUT_OF_RANGE as catchableByTry=true in StandardErrorCode
- Refactor TryFunction.propagateIfUnhandled() to use isCatchableByTry()
- Add comprehensive unit tests for ErrorCode and StandardErrorCode
@feilong-liu feilong-liu merged commit 6616215 into prestodb:master Jan 16, 2026
111 of 112 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

from:Meta PR from Meta

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants