Skip to content

Conversation

@asolntsev
Copy link
Contributor

@asolntsev asolntsev commented Jan 25, 2026

User description

💥 What does this PR do?

Adds valuable information to JSON parsing exception: which field was invalid.

🔧 Example

Example of JSON parsing exception that was not clean enough:

org.openqa.selenium.json.JsonException: java.lang.NumberFormatException: Character array is missing "e" notation exponential mark.
Build info: version: '4.40.0-SNAPSHOT', revision: '048a50178d*'
System info: os.name: 'Mac OS X', os.arch: 'aarch64', os.version: '26.2', java.version: '17.0.17'
Driver info: driver.version: unknown
	at org.openqa.selenium.json.NumberCoercer.lambda$apply$0(NumberCoercer.java:68)
	at org.openqa.selenium.json.JsonTypeCoercer.lambda$buildCoercer$6(JsonTypeCoercer.java:171)
	at org.openqa.selenium.json.JsonTypeCoercer.coerce(JsonTypeCoercer.java:146)
	at org.openqa.selenium.json.JsonInput.read(JsonInput.java:428)
	at org.openqa.selenium.bidi.script.RemoteValue.fromJson(RemoteValue.java:136)
	... 53 more
Caused by: java.lang.NumberFormatException: Character array is missing "e" notation exponential mark.
	at java.base/java.math.BigDecimal.<init>(BigDecimal.java:645)
	at java.base/java.math.BigDecimal.<init>(BigDecimal.java:471)
	at java.base/java.math.BigDecimal.<init>(BigDecimal.java:900)
	at org.openqa.selenium.json.NumberCoercer.lambda$apply$0(NumberCoercer.java:66)

See #16918

🔄 Types of changes

  • Bug fix (backwards compatible)

PR Type

Bug fix


Description

  • Enriches JSON parsing exceptions with specific field/value information

  • Improves error messages in numeric, instant, and object coercion

  • Adds detailed context about which values failed to parse

  • Includes comprehensive test coverage for error scenarios


Diagram Walkthrough

flowchart LR
  A["JSON Parsing Errors"] -->|Add context| B["Field/Value Information"]
  B -->|NumberCoercer| C["Numeric Value Details"]
  B -->|InstantCoercer| D["Timestamp Format Details"]
  B -->|InstanceCoercer| E["Object Property Details"]
  C -->|Tests| F["Validation Coverage"]
  D -->|Tests| F
  E -->|Tests| F
Loading

File Walkthrough

Relevant files
Error handling
InstanceCoercer.java
Add context to field and method invocation errors               

java/src/org/openqa/selenium/json/InstanceCoercer.java

  • Enhanced exception messages when setting fields with context about
    class, field name, and value
  • Improved exception messages when invoking setter methods with method
    signature details
  • Simplified getClss() method with early returns and added type
    information to error message
+14/-11 
InstantCoercer.java
Improve instant parsing with better error messages             

java/src/org/openqa/selenium/json/InstantCoercer.java

  • Changed from BigDecimal to BigInteger for parsing digit-only strings
    as timestamps
  • Added pattern matching to detect numeric-only timestamp strings
  • Enhanced error messages with formatted strings showing the invalid
    timestamp value
  • Improved exception chaining with original cause exceptions
+15/-7   
Json.java
Add context to JSON conversion errors                                       

java/src/org/openqa/selenium/json/Json.java

  • Added descriptive message to JSON conversion exception indicating what
    value failed to convert
+1/-1     
JsonInput.java
Improve number parsing error chain                                             

java/src/org/openqa/selenium/json/JsonInput.java

  • Added original exception as cause to number parsing error for better
    error chain context
+1/-1     
NumberCoercer.java
Add numeric value context to coercion errors                         

java/src/org/openqa/selenium/json/NumberCoercer.java

  • Extracted numeric string value to variable for better error reporting
  • Enhanced exception message to show the actual invalid numeric string
    value
  • Improved exception chaining with original cause
+4/-2     
Bug fix
ObjectCoercer.java
Add generic type parameter                                                             

java/src/org/openqa/selenium/json/ObjectCoercer.java

  • Added generic type parameter to class declaration for type safety
+1/-1     
Tests
JsonTest.java
Add comprehensive JSON parsing error tests                             

java/test/org/openqa/selenium/json/JsonTest.java

  • Added new test classes NumericValues, BooleanValues, and Dates for
    comprehensive testing
  • Added tests for numeric value parsing with valid and invalid inputs
  • Added tests for boolean value parsing with error scenarios
  • Added tests for instant parsing from timestamps and ISO format with
    detailed error validation
  • Updated existing instant parsing test to use new test structure
  • Enhanced existing boolean and string parsing tests with assertions
+125/-10
Dependencies
BUILD.bazel
Add jspecify dependency                                                                   

java/test/org/openqa/selenium/json/BUILD.bazel

  • Added org.jspecify:jspecify dependency for nullable annotations
    support
+1/-0     

Example of JSON parsing exception that was not clean enough:

```
org.openqa.selenium.json.JsonException: java.lang.NumberFormatException: Character array is missing "e" notation exponential mark.
Build info: version: '4.40.0-SNAPSHOT', revision: '048a50178d*'
System info: os.name: 'Mac OS X', os.arch: 'aarch64', os.version: '26.2', java.version: '17.0.17'
Driver info: driver.version: unknown
	at org.openqa.selenium.json.NumberCoercer.lambda$apply$0(NumberCoercer.java:68)
	at org.openqa.selenium.json.JsonTypeCoercer.lambda$buildCoercer$6(JsonTypeCoercer.java:171)
	at org.openqa.selenium.json.JsonTypeCoercer.coerce(JsonTypeCoercer.java:146)
	at org.openqa.selenium.json.JsonInput.read(JsonInput.java:428)
	at org.openqa.selenium.bidi.script.RemoteValue.fromJson(RemoteValue.java:136)
	... 53 more
Caused by: java.lang.NumberFormatException: Character array is missing "e" notation exponential mark.
	at java.base/java.math.BigDecimal.<init>(BigDecimal.java:645)
	at java.base/java.math.BigDecimal.<init>(BigDecimal.java:471)
	at java.base/java.math.BigDecimal.<init>(BigDecimal.java:900)
	at org.openqa.selenium.json.NumberCoercer.lambda$apply$0(NumberCoercer.java:66)
```

See SeleniumHQ#16918
@asolntsev asolntsev added this to the 4.41.0 milestone Jan 25, 2026
@asolntsev asolntsev self-assigned this Jan 25, 2026
@selenium-ci selenium-ci added C-java Java Bindings B-build Includes scripting, bazel and CI integrations labels Jan 25, 2026
@asolntsev asolntsev requested a review from iampopovich January 25, 2026 11:23
@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Jan 25, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Sensitive data exposure

Description: Exception messages now embed raw parsed content (e.g., builder and input), and similar new
messages across the PR also echo user-provided values (toConvert, field values,
timestamps, numeric strings), which can inadvertently expose sensitive data in logs or
error telemetry when JSON contains secrets/PII.
JsonInput.java [253-262]

Referred Code
try {
  if (!decimal) {
    return Long.valueOf(builder.toString());
  }

  return new BigDecimal(builder.toString()).doubleValue();
} catch (NumberFormatException e) {
  throw new JsonException("Unable to parse to a number: " + builder + ". " + input, e);
}
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: 🏷️
Sensitive data exposure: New exception messages include class/field names and the raw value (and in other files the
raw JSON/input), which could expose sensitive user-provided data depending on where these
exceptions are surfaced.

Referred Code
throw new JsonException(
    String.format(
        "Cannot set %s.%s = %s",
        instance.getClass().getName(), field.getName(), value),
    e);

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: 🏷️
Unsanitized input in errors: The thrown JsonException now appends input and the parsed number text to the error
message, which may inadvertently echo untrusted JSON content (potentially including
secrets) back to callers.

Referred Code
  throw new JsonException("Unable to parse to a number: " + builder + ". " + input, e);
}

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link
Contributor

qodo-code-review bot commented Jan 25, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
support signed timestamps

Update the regex in InstantCoercer to allow an optional leading sign (+ or -) to
correctly parse negative epoch timestamps as strings.

java/src/org/openqa/selenium/json/InstantCoercer.java [30]

-private static final Pattern DIGITS_ONLY = Pattern.compile("\\d+");
+private static final Pattern DIGITS_ONLY = Pattern.compile("[-+]?\\d+");
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: This is a valid feature enhancement to support negative timestamps (pre-1970 epoch), which improves the completeness of the timestamp parsing logic.

Medium
Avoid calling toString on converted object

In the exception message for JSON conversion failure, use the object's class
name instead of its toString() representation to prevent potential performance
issues or overly verbose logs.

java/src/org/openqa/selenium/json/Json.java [136]

-throw new JsonException("Cannot convert " + toConvert + " to json", e);
+throw new JsonException("Cannot convert " + toConvert.getClass().getName() + " to json", e);
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly points out that calling toString() on an arbitrary object in an exception message can be problematic, and using getClass().getName() is a safer and more robust approach for logging and debugging.

Low
include class name in exception

In InstanceCoercer, improve the exception message for instantiation failure by
using the target class name (target.getName()) instead of the generic Type
object.

java/src/org/openqa/selenium/json/InstanceCoercer.java [166-168]

 } catch (ReflectiveOperationException e) {
-  throw new JsonException("Cannot create instance of " + type, e);
+  throw new JsonException("Cannot create instance of " + target.getName(), e);
 }
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion improves the clarity of the exception message by using the class name instead of the Type's toString() representation, which provides a more readable and helpful error for debugging.

Low
simplify number parse error

Simplify the number parsing error message in JsonInput by removing the input
object's string representation, focusing only on the invalid number that failed
to parse.

java/src/org/openqa/selenium/json/JsonInput.java [261]

-throw new JsonException("Unable to parse to a number: " + builder + ". " + input, e);
+throw new JsonException("Unable to parse to a number: " + builder, e);
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies that including the entire input object's string representation in the error message is unnecessary and can be verbose, making the exception message cleaner and more focused.

Low
Learned
best practice
Trim and validate timestamp strings

Trim and validate the JSON string value before matching/parsing so
whitespace-only or padded timestamps are handled consistently and errors are
clearer.

java/src/org/openqa/selenium/json/InstantCoercer.java [44-61]

 } else if (JsonType.STRING.equals(token)) {
-  String raw = jsonInput.nextString();
+  String raw = jsonInput.nextString().trim();
+  if (raw.isEmpty()) {
+    throw new JsonException("\"\" does not look like an Instant");
+  }
   if (DIGITS_ONLY.matcher(raw).matches()) {
     try {
       return Instant.ofEpochMilli(new BigInteger(raw).longValueExact());
     } catch (NumberFormatException | ArithmeticException invalidLong) {
       throw new JsonException(
           String.format("\"%s\" is not a valid timestamp", raw), invalidLong);
     }
   }
   try {
     TemporalAccessor parsed = DateTimeFormatter.ISO_INSTANT.parse(raw);
     return Instant.from(parsed);
   } catch (DateTimeParseException invalidDateTime) {
     throw new JsonException(
         String.format("\"%s\" does not look like an Instant", raw), invalidDateTime);
   }
 }
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Add explicit validation/guards at integration boundaries by trimming and checking inputs before use.

Low
  • Update

…rameAndClick()

Failure example:

```
canMoveMouseToAnElementInAnIframeAndClick() (org.openqa.selenium.interactions.CombinedInputActionsTest)
org.openqa.selenium.WebDriverException: InactiveActor: Actor is no longer active
Build info: version: '4.41.0-SNAPSHOT', revision: 'Unknown'
System info: os.name: 'Linux', os.arch: 'amd64', os.version: '6.1.0-42-cloud-amd64', java.version: '21.0.4'
Driver info: org.openqa.selenium.firefox.FirefoxDriver
Command: [f2b94f3c-a2cc-43b0-b869-6b313b9515b1, actions {actions=[org.openqa.selenium.interactions.Sequence@562919fe]}]
Capabilities {acceptInsecureCerts: true, browserName: firefox, browserVersion: 148.0, moz:accessibilityChecks: false, moz:buildID: 20260123090351, moz:geckodriverVersion: 0.36.0, moz:headless: false, moz:platformVersion: 6.1.0-42-cloud-amd64, moz:processID: 12338, moz:profile: /tmp/rust_mozprofileC1s3za, moz:shutdownTimeout: 60000, moz:webdriverClick: true, moz:windowless: false, pageLoadStrategy: normal, platformName: linux, proxy: Proxy(), setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, userAgent: Mozilla/5.0 (X11; Linux x86..., webSocketUrl: ws://127.0.0.1:42879/sessio...}
Session ID: f2b94f3c-a2cc-43b0-b869-6b313b9515b1
	at org.openqa.selenium.remote.ErrorCodec.decode(ErrorCodec.java:169)
	at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:142)
	at org.openqa.selenium.remote.codec.w3c.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
	at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:223)
	at org.openqa.selenium.remote.service.DriverCommandExecutor.invokeExecute(DriverCommandExecutor.java:216)
	at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:174)
	at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:602)
	at org.openqa.selenium.remote.RemoteWebDriver.perform(RemoteWebDriver.java:697)
	at org.openqa.selenium.interactions.Actions$BuiltAction.perform(Actions.java:616)
	at org.openqa.selenium.interactions.Actions.perform(Actions.java:581)
	at org.openqa.selenium.interactions.CombinedInputActionsTest.canMoveMouseToAnElementInAnIframeAndClick(CombinedInputActionsTest.java:251)
```
@asolntsev asolntsev requested a review from joerg1985 January 25, 2026 17:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B-build Includes scripting, bazel and CI integrations C-java Java Bindings Review effort 3/5

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants