kotlinx.rpc 0.9.1 Help

Migration to 0.8.0

Version 0.8.0 brings a lot of changes, mainly targeted to remove inherently broken functionality and simplify kRPC protocol where possible. This is reflected in the number of breaking changes and deprecations.

This page aims to cover all such changes and associated migration instructions.

Strict mode enforcement

Strict mode is now enforced and can't be disabled. See Strict mode for detailed migrations.

kRPC protocol changes

The following changes are reflected in the kRPC protocol on the wire:

  • KrpcServer doesn't send CANCELLATION_ACK messages anymore.

  • KrpcClient sends REQUEST cancellation messages for every individually finished call, canceled or finished successfully

Though changes should not affect most users, for those who like to look at the wire it might be useful to know.

Behavioral changes

Some changes in the behavior of kRPC clients and servers:

  • Lifetime for client-side streams is changed.

    Previously, the stream scopes bounded client-side streams. However, stream scopes are completely removed now, so the client-side streams lifetime is now bound to the request's lifetime. This means that when the function returns, every client stream is closed.

  • Serial format is now only constructed once per client.

    Previously, the serial format was constructed once per RPC call. The serial format can be passed using the KrpcConfig. And the builder code was executed once per every call.

    Now this behavior is removed. The serial format is constructed once per client.

  • Services are now instantiated once per service type (Rpc FQ name) and not once per client-side instance.

    Services lost their CoroutineScopes (see Incompatible API changes). That means that there are no individual lifetimes for each service instance now. Instead, now each service stub on a client is merely a proxy for function calls. And on the server side, the service implementation is instantiated once per service type. To control this behavior more granularly on the server, new deregisterService function is introduced.

  • Handshake is now cold.

    Previously, the handshake was executed on client creation. Now, the handshake is executed on the first RPC request.

Incompatible API changes

  • RpcClient.callServerStreaming lost its default implementation:

    interface RpcClient { fun <T> callServerStreaming(call: RpcCall): Flow<T> { error("Not implemented") } }
    interface RpcClient { fun <T> callServerStreaming(call: RpcCall): Flow<T> }
  • @Rpc services lost their CoroutineScope:

    val service = client.withService<MyService>() assert(service is CoroutineScope) // OK
    val service = client.withService<MyService>() assert(service is CoroutineScope) // fail
  • RpcClient lost its CoroutineScope:

    interface RpcClient : CoroutineScope
    interface RpcClient
  • RpcServer lost its CoroutineScope:

    interface RpcServer : CoroutineScope
    interface RpcServer
  • RpcServer.registerService factory parameter changes type from (CoroutineContext) -> Service to () -> Service:

    interface RpcServer { fun <@Rpc Service : Any> registerService( serviceKClass: KClass<Service>, serviceFactory: (CoroutineContext) -> Service, ) } inline fun <@Rpc reified Service : Any> RpcServer.registerService( noinline serviceFactory: (CoroutineContext) -> Service, ) { registerService(Service::class, serviceFactory) }
    interface RpcServer { fun <@Rpc Service : Any> registerService( serviceKClass: KClass<Service>, serviceFactory: () -> Service, ) } inline fun <@Rpc reified Service : Any> RpcServer.registerService( noinline serviceFactory: () -> Service, ) { registerService(Service::class, serviceFactory) }
  • RpcServer.registerService lost its CoroutineContext parameter:

    interface RpcServer
    interface RpcServer { fun <@Rpc Service : Any> deregisterService( serviceKClass: KClass<Service>, ) }
  • RpcCall changed parameter name and type for function's data:

    class RpcCall( val descriptor: RpcServiceDescriptor<*>, val callableName: String, val data: Any?, val serviceId: Long, )
    class RpcCall( val descriptor: RpcServiceDescriptor<*>, val callableName: String, val parameters: Array<Any?>, val serviceId: Long, )
  • For Ktor, HttpClient.rpc extension function is now non-suspendable.

  • KtorRpcClient.webSocketSession is now wrapped in Deferred:

    interface KtorRpcClient : RpcClient { val webSocketSession: WebSocketSession }
    interface KtorRpcClient : RpcClient { val webSocketSession: Deferred<WebSocketSession> }
  • KrpcClient abstract class has two new abstract methods: initializeConfig and initializeTransport. They can be used to delay transport initialization until the first RPC call.

    To mimic old behavior, InitializedKrpcClient can be used:

    class MyClient( config: KrpcConfig, transport: KrpcTransport, ) : KrpcClient(config, transport)
    class MyClient( config: KrpcConfig, transport: KrpcTransport, ) : InitializedKrpcClient(config, transport)

API removals

The following APIs are removed:

  • kotlinx.rpc.RpcClient.callAsync - previously deprecated

  • kotlinx.rpc.RpcClient.provideStubContext

  • kotlinx.rpc.registerPlainFlowField - previously deprecated

  • kotlinx.rpc.registerSharedFlowField - previously deprecated

  • kotlinx.rpc.registerStateFlowField - previously deprecated

  • kotlinx.rpc.awaitFieldInitialization - previously deprecated

  • kotlinx.rpc.UninitializedRpcFieldException - previously deprecated

  • kotlinx.rpc.UninitializedRPCFieldException - previously deprecated

  • kotlinx.rpc.RpcEagerField - previously deprecated

  • kotlinx.rpc.RPCCall - previously deprecated alias

  • kotlinx.rpc.RPCClient - previously deprecated alias

  • kotlinx.rpc.descriptor.RpcInvokator.Field - previously deprecated

  • kotlinx.rpc.descriptor.RpcServiceDescriptor.getFields - previously deprecated

  • kotlinx.rpc.krpc.StreamScope - previously deprecated

  • kotlinx.rpc.krpc.streamScoped - previously deprecated

  • kotlinx.rpc.krpc.withStreamScope - previously deprecated

  • kotlinx.rpc.krpc.invokeOnStreamScopeCompletion - previously deprecated

  • kotlinx.rpc.krpc.KrpcConfigBuilder.SharedFlowParametersBuilder - previously deprecated

  • kotlinx.rpc.krpc.KrpcConfigBuilder.sharedFlowParameters - previously deprecated

  • kotlinx.rpc.krpc.KrpcConfig.sharedFlowBuilder - previously deprecated

  • kotlinx.rpc.krpc.RPCTransport - previously deprecated alias

  • kotlinx.rpc.krpc.RPCTransportMessage - previously deprecated alias

  • kotlinx.rpc.krpc.RPCConfigBuilder - previously deprecated alias

  • kotlinx.rpc.krpc.client.KRPCClient - previously deprecated alias

  • kotlinx.rpc.krpc.server.RPCServer - previously deprecated alias

  • kotlinx.rpc.krpc.server.KRPCServer - previously deprecated alias

  • kotlinx.rpc.krpc.serialization.RPCSerialFormat - previously deprecated alias

  • kotlinx.rpc.krpc.serialization.RPCSerialFormatBuilder - previously deprecated alias

  • kotlinx.rpc.krpc.serialization.RPCSerialFormatConfiguration - previously deprecated alias

  • kotlinx.rpc.krpc.ktor.client.RPC - previously deprecated alias

  • kotlinx.rpc.krpc.ktor.client.installRPC - previously deprecated alias

  • kotlinx.rpc.krpc.ktor.server.RPC - previously deprecated alias

  • kotlinx.rpc.krpc.ktor.server.RPCRoute - previously deprecated alias

Deprecations

  • Gradle's rpc.strict extension is deprecated with an error. Strict mode is now enforced and can't be disabled. See Strict mode for detailed migrations.

  • RemoteService is deprecated with error; services are no longer having this interface added during the compilation. See Behavioral changes for services' lifetime information.

Other changes

  • MISSING_RPC_ANNOTATION compiler inspection is removed.

  • ABI incompatible change: KrpcTransport.receiveCatching is now an extension function.

  • The following compiler plugin options are removed:

    • strict-stateFlow

    • strict-sharedFlow

    • strict-nested-flow

    • strict-stream-scope

    • strict-suspending-server-streaming

    • strict-not-top-level-server-flow

    • strict-fields

Last modified: 25 June 2025