4.1.1

(fix): Fix custom-dependencies not being able to override bundled dependency versions (OkHttp, Jackson, etc.). Previously, custom dependencies were appended alongside bundled ones, so Gradle’s dependency resolution would pick the higher version. Custom dependencies now replace any bundled dependency with the same group and artifact, allowing users to pin specific versions for CVE remediation or compatibility.

4.1.0

(feat): Add maxRetries custom config option to override the default maximum number of retries for failed requests. The default remains 2 when not specified.


4.0.9

(fix): Fix RetryInterceptor sharing a single ExponentialBackoff instance across all requests. Once the retry budget was exhausted by any request, no further retries were attempted for the lifetime of the client. Each request now gets its own backoff instance.


4.0.8

(fix): Fix multipart form data string fields being JSON-encoded with writeValueAsString(), which wraps values in literal quote characters. String fields, primitives, and enums now use plain string conversion instead of JSON serialization. Complex types (objects, maps) continue to use JSON serialization as before.


4.0.7

(fix): Thread endpoint ID through dynamic snippet generator to differentiate generated snippets by endpoint.

4.0.6

(fix): Fix custom license not being resolved in build.gradle when using local generation (--local). The license file is mounted at /tmp/LICENSE inside Docker, but the generator was looking for it at a relative path that did not exist. The generator now checks /tmp/<filename> as a fallback. Additionally, markdown formatting (headers, bold, etc.) is now stripped from the first line of the license file when used as the license name.

4.0.5

(fix): Fix generated README exception handling snippet using {org}ApiException instead of {clientClassName}ApiException when client-class-name is specified in the Java custom config. The README now uses the same exception type name that is actually generated in the SDK.


4.0.4

(fix): Fix query parameters being serialized into the JSON request body for endpoints that combine query parameters with an inlined request body. Query parameter getters on wrapped request classes now use @JsonIgnore instead of @JsonProperty, preventing them from appearing in both the URL query string and the POST body.


4.0.3

(fix): Fix WebSocket handleIncomingMessage() using Fern-internal message IDs (e.g. AgentV1Welcome, ListenV1Results) instead of the wire discriminant values from the spec (e.g. Welcome, Results). This caused all incoming message handlers to never fire, falling through to the unknown type handler.

The generator now extracts wire discriminant values from each message body’s type property — resolving literal values (e.g. literal<"Welcome">) and enum values (e.g. enum[Flushed, Cleared]) — and dispatches via a switch statement on those values. This aligns with the approach used by the Python generator.

(fix): WebSocket handler registration methods and field names now use wire discriminant values instead of Fern-internal prefixed names. For example, onAgentV1Welcome(handler) is now onWelcome(handler), and onAgentV1PromptUpdated(handler) is now onPromptUpdated(handler). Methods that were already backed by a custom x-fern-sdk-method-name (e.g. onFunctionCallResponse) are unchanged.

(chore): Improve generated WebSocket client code quality: use a string literal for static URL paths instead of StringBuilder, remove dead if/else branches in async sendMessage(), consolidate redundant catch blocks in message dispatch, and correct Javadoc articles (“a” vs “an”) for type names starting with vowels.


4.0.2

(fix): Fix binary file upload for wrapped request endpoints (endpoints with query parameters alongside an application/octet-stream body). The body type is now byte[] instead of String, and the request is sent via InputStreamRequestBody instead of String.valueOf().getBytes(UTF_8), which was corrupting binary data.

4.0.1

(fix): Fix generated snippets producing OptionalNullable.of(...) for fields that are only optional (not nullable) when collapse-optional-nullable is enabled.


4.0.0

(feat): Breaking change for WebSocket users only. REST-only SDKs are unaffected — no code changes required.

Overhaul generated WebSocket clients. The generated API is restructured around a factory → configure → connect lifecycle that separates client creation from connection parameters:

1// Create client from the service tree — no connection params yet
2V1WebSocketClient ws = client.listen().v1WebSocket();
3
4// Register handlers before connecting
5ws.onListenV1Results(results ->
6 System.out.println(results.getChannel().getAlternatives()));
7ws.onError(error -> error.printStackTrace());
8
9// Connect with channel-specific options (required params enforced at compile time)
10ws.connect(V1ConnectOptions.builder()
11 .model(ListenV1Model.NOVA3)
12 .encoding(ListenV1Encoding.LINEAR16)
13 .sampleRate(16000)
14 .build());
15
16// Stream audio and disconnect
17ws.sendMedia(audioBytes);
18ws.disconnect();

Query parameters move from constructor to connect(). The factory method (client.listen().v1WebSocket()) now takes no channel-specific arguments. All query parameters are passed via a builder-pattern ConnectOptions object to connect(), matching the Python SDK’s design. Required parameters use staged builders so missing fields are caught at compile time.

AutoCloseable — clients implement AutoCloseable for try-with-resources, calling disconnect() automatically on scope exit.

Configurable reconnectionreconnectOptions(ReconnectOptions) lets callers tune max retries, backoff delay, and queue size before calling connect().

Generic onMessage(Consumer<String>) handler — fires for every incoming text frame with the raw JSON string, before type-specific dispatch. Useful for logging or custom routing.

Binary WebSocket support — channels that define binary messages now generate typed send and receive methods. Binary frames queue when disconnected and flush on reconnect, matching text behavior.

Shared core typesDisconnectReason and WebSocketReadyState are generated once in the core package instead of duplicated as inner classes inside every WebSocket client.

Thread safety — all handler fields are now volatile so handlers registered from the main thread are visible to OkHttp callback threads. Previously only readyState was volatile.

x-fern-sdk-method-name support — WebSocket send/receive methods use the custom method name from the Fern config when set.

Also removes the deprecated hasWebSocketInstance() method and fires onError for unrecognized incoming message types instead of silently dropping them.

(fix): Fix WebSocket connect() crashing with NullPointerException when the environment URL uses wss:// or ws:// schemes. OkHttp’s HttpUrl.parse() only accepts http/https, so the client now rewrites the scheme before parsing and null-checks the result.

(fix): Fix WebSocket clients always calling environment().getUrl(), which does not exist on multi-URL environment classes. The generator now resolves the correct per-URL getter (e.g. environment().getAgentURL()) based on the channel’s baseUrl field in the IR, matching the pattern already used by REST endpoints.

(fix): Fix WebSocket clients not sending authentication headers when the channel’s auth field is false in the IR. Previously, headers were only applied when websocketChannel.getAuth() was true. connect() now unconditionally applies clientOptions.headers() to the upgrade request, ensuring bearer tokens, API keys, and custom headers are always sent regardless of the channel’s auth configuration.

(fix): Fix WebSocket message serialization wrapping every outgoing message in a {"type": "...", "body": {...}} envelope and expecting the same format for incoming messages. Messages are now serialized directly as flat JSON (the discriminated union already contains the type field), and incoming messages are deserialized from the root JSON object instead of extracting a nested body sub-field.

(fix): Fix binary file upload endpoints (application/octet-stream) serializing the request body through Jackson, which corrupted binary data with JSON string escaping. These endpoints now send raw bytes via InputStreamRequestBody.

3.44.6

(fix): Fix duplicate discriminator keys in union serialization. When a discriminated union variant uses @JsonUnwrapped and the wrapped object already contains the discriminant property (e.g., “type”), the serialized JSON previously contained the key twice. The generator now adds a field-level @JsonIgnoreProperties annotation with allowSetters = true on @JsonUnwrapped fields to suppress the duplicate during serialization while preserving deserialization.

3.44.5

(fix): Fix floating-point serialization of integer-valued doubles. Values like 24000.0 are now serialized as 24000 instead of 24000.0 in JSON output. This prevents API rejections for fields defined as type: number when the value happens to be a whole number. Non-integer double values like 3.14 continue to serialize normally.

3.44.4

(fix): Fix dynamic snippet compilation errors for objects with required fields in staged builders. When an endpoint example omits a required property, the snippet generator now fills in a type-appropriate default value instead of producing an invalid .builder().build() call that skips mandatory builder stages.

(fix): Fix dynamic snippet builder ordering when default values are added for missing required properties. Properties are now re-sorted to match schema declaration order after defaults are injected, ensuring Java staged builder method calls follow the correct sequence.

(fix): Fix undiscriminated union variant matching selecting incorrect variants when example data doesn’t match. Required properties and their nested types are now validated during matching, so variants with mismatched enum values or missing required fields are correctly rejected.

(fix): Fix hardcoded com.seed.api.core.OptionalNullable import in generated README OptionalNullable documentation. The import now uses the correct dynamic package name for the SDK being generated.

(fix): Fix incorrect raw response type name in generated README. The “Access Raw Response Data” section now uses the correct {BaseNamePrefix}HttpResponse class name (e.g., Auth0ApiHttpResponse) instead of the endpoint-derived name (e.g., CreateHttpResponse).

(fix): Fix missing environment URL variables in generated README Usage example. Builder parameters like tenantDomain from OpenAPI server URL templates are now included in the Usage snippet alongside auth parameters.

3.44.3

(fix): Fix auth header prefix missing trailing space.


3.44.2

(fix): Generate named Java wrapper classes for unknown type aliases. Previously, when an API schema had no type and no properties (representing an “any” type), the generator dropped the named type definition and inlined Object wherever it was referenced. Unknown type aliases now generate a proper wrapper class (e.g. DocumentedUnknownType) based on java.lang.Object, consistent with how other alias types are handled.


3.44.1

(fix): Fix enable-forward-compatible-enums config flag being ignored in download files mode. The flag was missing from JavaSdkDownloadFilesCustomConfig, so enable-forward-compatible-enums: false in generators.yml had no effect when using --local generation.