Summary
Some HTTP APIs return Java exception class names and unaudited Throwable.getMessage() values to clients when handling exceptions, for example:
{
"Error": "class java.lang.NullPointerException : null"
}
This proposal standardizes client-facing error messages from standard HTTP Servlets in phase 1:
- Existing messages are temporarily preserved for exceptions explicitly covered for compatibility.
- All other exceptions return the stable message
internal server error.
- Java exception class names are no longer returned to clients, nor are raw exception messages that are not explicitly allowed.
Phase 1 changes only the content and format of failure responses. Successful responses, request rules, HTTP status codes, gRPC behavior, and JSON-RPC behavior remain unchanged.
Problem
Motivation
Returning runtime exception information directly to clients has the following problems:
- It provides little value to clients in diagnosing or handling request failures.
- Exception messages may change with JDK or dependency versions and are unsuitable as a stable, long-term API contract.
Current State
Before this change, standard HTTP error-response paths behave inconsistently:
Util.processError returns a concatenation of the Java exception class name and raw message.
- Some Servlets bypass
Util.processError and directly return exception class names or Throwable.getMessage() values.
- Two Solidity query endpoints return plain-text error bodies instead of standard JSON.
Limitations and Risks
- Clients that depend on Java exception class names, raw exception messages, or plain-text error bodies will observe compatibility changes.
- To limit the compatibility impact of phase 1, non-blank raw messages from three exact exception types are temporarily preserved.
Proposed Solution
Proposed Design
1. Standardize HTTP error-response paths
The standard Servlet JSON and text error-response paths governed by phase 1 are routed through Util.processError, which centrally determines the final client-facing message.
2. Preserve compatibility messages for three exact exception types
For compatibility with existing clients, Util.processError preserves raw messages only for the following exact runtime types:
JsonFormat.ParseException
ContractValidateException
MaintenanceUnavailableException
These three cases are legacy residuals temporarily retained for compatibility with existing behavior.
3. Preserve two exactly matched fixed messages
The following existing fixed responses are preserved only when both the exact exception type and exact message constant match:
IllegalAccessException("lack of computing resources")
IllegalArgumentException(EVENTS_DEPRECATED_MSG)
- Used by the Scan Events deprecation check.
4. Fail closed for all other exceptions
Except for the explicitly allowed compatibility branches above, exceptions must not expose Java exception class names or raw messages to clients. This includes, but is not limited to:
NullPointerException
- Array or collection bounds exceptions
- Ordinary
IllegalArgumentException
- Other unmapped runtime or internal exceptions
They return:
{
"Error": "internal server error"
}
Key Changes
- The change is limited to the HTTP Servlet layer in the
framework module.
- Standard JSON and text error-response paths governed by phase 1 are routed through
Util.processError.
- Java exception class prefixes are removed from standard error responses.
Util.processError applies compatibility rules using exact runtime types and fixed message constants.
- Exceptions that are not explicitly allowed return
internal server error.
- The two Solidity query endpoints change their error bodies from plain text to standard
{"Error":"..."} JSON.
Impact
- Security
- Standard generic and unclassified error-response paths no longer return Java exception class names or uncontrolled raw messages.
- The three compatibility branches that retain raw messages are separately registered and tracked as known residuals.
- Stability
- Unknown exceptions use a stable message instead of depending on JDK or library exception messages.
- Performance
- The change adds only lightweight exception-type and fixed-message comparisons.
- Normal request paths are unaffected.
- Developer Experience
- Standard HTTP error-response behavior is centralized in
Util.processError.
Compatibility
| Item |
Result |
| Breaking Change |
Yes, limited to some HTTP failure responses. Some error messages will change, and the two Solidity query endpoints will return JSON instead of plain-text error bodies. This change must be included in the release notes. |
| Default Behavior Change |
Yes. Only failure responses change; successful responses remain unchanged. |
| Migration Required |
Conditional. Clients that rely only on successful responses or documented response fields require no migration. Clients that depend on Java exception class names, raw exception messages, or plain-text Solidity error bodies must be updated. |
Affected clients should:
- Read the
Error field from the standard JSON response.
- Stop depending on Java exception class names.
- Stop treating JDK or third-party exception messages as a stable API contract.
- Handle unknown server errors as
internal server error.
The following behavior remains unchanged:
- Existing HTTP status codes
- Status codes and response content for successful requests
- Request parameters and validation rules
- gRPC API behavior
- JSON-RPC API behavior
Acceptance Criteria
{
"Error": "internal server error"
}
Follow-up
Future phases will:
- Distinguish client parameter errors from internal server errors based on the specific HTTP input source.
- Avoid treating JDK or third-party exception messages as part of the long-term API contract.
Additional Notes
-
Do you have ideas regarding implementation? Yes. Route the in-scope standard Servlet error paths through Util.processError, and use exact runtime-type and fixed-message matching to determine the client-facing error message.
-
Are you willing to implement this feature? Yes.
Summary
Some HTTP APIs return Java exception class names and unaudited
Throwable.getMessage()values to clients when handling exceptions, for example:{ "Error": "class java.lang.NullPointerException : null" }This proposal standardizes client-facing error messages from standard HTTP Servlets in phase 1:
internal server error.Phase 1 changes only the content and format of failure responses. Successful responses, request rules, HTTP status codes, gRPC behavior, and JSON-RPC behavior remain unchanged.
Problem
Motivation
Returning runtime exception information directly to clients has the following problems:
Current State
Before this change, standard HTTP error-response paths behave inconsistently:
Util.processErrorreturns a concatenation of the Java exception class name and raw message.Util.processErrorand directly return exception class names orThrowable.getMessage()values.Limitations and Risks
Proposed Solution
Proposed Design
1. Standardize HTTP error-response paths
The standard Servlet JSON and text error-response paths governed by phase 1 are routed through
Util.processError, which centrally determines the final client-facing message.2. Preserve compatibility messages for three exact exception types
For compatibility with existing clients,
Util.processErrorpreserves raw messages only for the following exact runtime types:JsonFormat.ParseExceptionContractValidateExceptionMaintenanceUnavailableExceptionThese three cases are legacy residuals temporarily retained for compatibility with existing behavior.
3. Preserve two exactly matched fixed messages
The following existing fixed responses are preserved only when both the exact exception type and exact message constant match:
IllegalAccessException("lack of computing resources")IllegalArgumentException(EVENTS_DEPRECATED_MSG)4. Fail closed for all other exceptions
Except for the explicitly allowed compatibility branches above, exceptions must not expose Java exception class names or raw messages to clients. This includes, but is not limited to:
NullPointerExceptionIllegalArgumentExceptionThey return:
{ "Error": "internal server error" }Key Changes
frameworkmodule.Util.processError.Util.processErrorapplies compatibility rules using exact runtime types and fixed message constants.internal server error.{"Error":"..."}JSON.Impact
Util.processError.Compatibility
Affected clients should:
Errorfield from the standard JSON response.internal server error.The following behavior remains unchanged:
Acceptance Criteria
Standard Servlet error-response paths governed by phase 1 generate responses through
Util.processError.These paths no longer concatenate Java exception class names or directly return arbitrary
Throwable.getMessage()values.Only the exact runtime types
JsonFormat.ParseException,ContractValidateException, andMaintenanceUnavailableExceptionmay preserve non-blank raw messages.For those three types, a null, empty, or whitespace-only message results in
internal server error.The two fixed messages are returned only when both the exact exception type and exact message constant match.
All other exceptions return:
{ "Error": "internal server error" }If writing the error response to the client fails, at most one additional
debuglog entry is recorded.The two Solidity query endpoints return standard JSON error responses.
HTTP status codes, successful responses, request rules, gRPC behavior, and JSON-RPC behavior remain unchanged.
Follow-up
Future phases will:
Additional Notes
Do you have ideas regarding implementation? Yes. Route the in-scope standard Servlet error paths through
Util.processError, and use exact runtime-type and fixed-message matching to determine the client-facing error message.Are you willing to implement this feature? Yes.