Changelog
4.23.2
(fix): Fix InputStream upload overloads on multipart endpoints that have
non-file form fields. The overloads now take the generated request
object and serialize every companion multipart field alongside the
streamed file, instead of silently dropping them. The unused
File-typed parameter (including Optional<File>) is also removed
from these signatures. When the file property is inlined onto the
request object (inline-file-properties: true) and companion fields
exist, the stream overloads are no longer generated, since the file
cannot be separated from the request object.
4.23.1
(chore): Bump bundled @fern-api/generator-cli to 0.10.3. When the hosted auto-version analysis of the
full SDK diff fails, generator-cli now retries chunk-by-chunk instead of silently applying a
PATCH bump; any remaining unavailable or incomplete analysis adds a “Version bump not verified”
notice to the SDK PR body and disables automerge.
4.22.3
(fix): Honor package-prefix and package-layout for local-file-system output when the CLI
requests a full project (e.g. --generate-tests, --package, or self-hosted SDKs).
Previously these were dropped when converting the local-file-system config, so the root
package fell back to com.<org>.<api> instead of the configured prefix. Full-project local
output now also writes sources at their full package path (src/main/java/com/acme/...)
instead of stripping the prefix from the directory.
4.23.0
(feat): XML-encoded (TwiML) types now carry inline Javadoc on their user-facing API: the class itself gets the
type description, every Builder setter overload gets the property description, and child appenders
(say.break_(...), response.say(...)) document the child element plus @param/@return.
4.22.2
(fix): RetryInterceptor now applies the client timeout to each attempt individually instead of to the
whole retry loop. Previously a Retry-After wait as long as the timeout (e.g. Retry-After: 60
with the default 60s timeout) cancelled the call during the backoff sleep and surfaced
IOException: Canceled instead of retrying or returning the received 429. The call timeout is
paused while waiting for the backoff and restarted for each retry attempt, so a call that retries
may now take up to timeout * (maxRetries + 1) plus the backoff waits.
4.22.1
(fix): Closing the root client (or ClientOptions.close()) now disconnects any WebSocket clients that are still
connected before the SDK-owned OkHttp dispatcher is shut down, so they stop reconnecting cleanly instead of
failing asynchronously with InterruptedIOException: executor rejected. ClientOptions exposes isClosed();
WebSocket connect/reconnect attempts made after close, as well as OkHttpWebSocketFactory.create(...) when
constructed with a closed-check, fail fast with IllegalStateException("root client has been closed").
4.22.0
(feat): Generate the shared WebhooksHelper from the API-wide api.settings.webhook-signature
setting in generators.yml (IR sdkConfig.webhookSignatureVerification). The helper is
emitted even when the API definition models no webhooks; webhook-specific signature
overrides still produce their own named helpers.
(fix): Fix the generated ReconnectingWebSocketListener connection-timeout message, which was missing the
closing parenthesis after the retry attempt number (e.g. ... milliseconds (retry attempt #2).
4.21.2
(fix): RetryInterceptor no longer discards an API response it has already received (e.g. a 429)
when a later retry attempt fails, such as when the call timeout expires mid-retry. The
previous response is buffered and returned instead of surfacing a generic IOException.
4.21.1
(chore): Bump bundled @fern-api/generator-cli to 0.10.1. Auto-versioned MAJOR/MINOR bumps no longer
produce a version-only changelog.md block when the AI analysis returns an empty changelog
entry; the PR description, version bump reason, or commit message body is used instead.
4.21.0
(feat): Generated root clients (sync and async) now implement AutoCloseable. close() shuts down
the underlying OkHttpClient’s dispatcher executor and evicts its connection pool, but only
when the SDK created that OkHttpClient itself — a client supplied via Builder.httpClient(...)
is left running, since the caller owns its lifecycle. This lets short-lived applications (e.g.
CLIs, or code that finishes after using WebSockets) release the client’s background threads
instead of relying on JVM shutdown.
4.20.0
(feat): Object types with xml encoding metadata (e.g. TwiML defined via OpenAPI xml objects) now
implement XmlSerializable with toXml() and a static fromXml(String) parser, backed by new
core XmlWriter/XmlReader utilities. Builders gain per-child-element methods
(e.g. Response.builder().say(...)) and undiscriminated child unions dispatch fromXml by
element name. Builder.fromXml(String) returns a populated builder, unknown child elements are
preserved as XmlElements (readable via getAdditionalChildren(), addable via addChild(...))
and round-tripped by toXml(), and very large objects that use a builder-based constructor also
get fromXml. Types without xml metadata are unchanged.
4.19.3
(fix): Generated ReconnectingWebSocketListener now acknowledges peer-initiated close frames by
overriding onClosing, so OkHttp completes the close handshake and onClosed (and the
public disconnect lifecycle) fires for server-initiated closes. A no-status close (local
sentinel 1005) is acknowledged with 1000, since 1005 is not a wire-valid close code.
The reconnect decision is exposed as a protected boolean shouldReconnectAfterClose(WebSocket, int, String)
hook (default unchanged: code != 1000) so resource-specific subclasses can treat a
protocol-established terminal close as final. Adds send(String, Consumer<WebSocket>) /
sendBinary(ByteString, Consumer<WebSocket>) overloads that report which socket directly
accepted a message (not invoked for queued or dropped messages).
4.19.2
(fix): Respect custom OAuth token headers and prefixes for client credentials authentication.
4.19.1
(fix): Honor an endpoint’s retries: {disabled: true} configuration (the x-fern-retries OpenAPI
extension). A call to such an endpoint tags its request with a max-retries override of zero, so it
bypasses automatic retries regardless of the client-wide ClientOptions.maxRetries or a
per-request RequestOptions.maxRetries. Endpoints without the configuration are unchanged.
4.19.0
(fix): With respect-optional-request-body enabled, a call that leaves out an optional request body now
passes a null body to OkHttp instead of an empty one, so the request carries no body at all. The
methods OkHttp requires a body for (POST, PUT, PATCH) still send an empty body, which is what
endpoints with no request body at all already send.
(feat): Add a respect-optional-request-body option. When enabled, an endpoint whose request body the API
does not require also gets an overload without the body parameter, and calling that overload sends
no body. The body parameter keeps its own type, so alpha(String id, Body body) gains a sibling
alpha(String id) rather than becoming alpha(String id, Optional<Body> body). Examples that
supply no body render as client.alpha(id). That call also leaves out the Content-Type header,
which now only goes out when a body does. The option defaults to false, so existing signatures
and snippets are unchanged.
4.18.2
(fix): Build an empty request body in snippets for an endpoint example that omits a body the wrapped
request requires, instead of leaving the builder’s required body stage unset.
4.18.1
(fix): Fix the generated OAuth token supplier when the get-token request has required properties
other than the client credentials. The builder calls are now ordered by the request’s
required properties, so the staged builder’s stages are satisfied in order, and hardcoded
values (such as grant_type) are written using the property’s type, which means an
enumerated grant_type gets the generated enum constant instead of a string literal.
4.18.0
(feat): Add support for the FERN_JAVA_SKIP_FORMATTING environment variable. When set to a truthy
value (1, true, yes, or on), the generator skips the ./gradlew :spotlessApply pass
that normally runs after code generation, so generation makes no Gradle invocation at all.
This unblocks restricted networks that cannot reach the Gradle distribution or plugin
repositories, and shortens generation time.
4.17.1
(fix): Fixed wire tests generated for APIs with auth: any combining Basic and OAuth schemes.
Tests no longer assert both a Bearer and a Basic Authorization header on the same
request; only the OAuth Bearer assertion is emitted since the client sends the OAuth
token when OAuth credentials are configured.
4.17.0
(feat): Add opt-in allowUserAgentAppInfo config. When enabled, the generated client’s builder exposes
an appInfo(name, version, comment) option whose product token is appended to the User-Agent
header the SDK would otherwise send ({sdk}/{version} ... {name}/{version} ({comment})),
following RFC 9110. Disabled by default, so existing generated output is unchanged, and it
composes with includePlatformHeaders, the runtime-version jar-manifest path, the configured
user-agent template value, and the default {coordinate}/{version}. Caller-supplied values are
trimmed and sanitized (name/version percent-encoded to RFC 7230 tchars; comment delimiters,
control characters and any non-ASCII characters percent-encoded as UTF-8 bytes so OkHttp’s header
validation never rejects them), so untrusted values cannot inject header content. Still overridable
by an explicit User-Agent and suppressed by omit-fern-headers.