From c0da54b588d349a85518915e72140a1df48765c5 Mon Sep 17 00:00:00 2001 From: Michael Ilyin Date: Tue, 21 Jul 2026 12:33:23 +0200 Subject: [PATCH 1/2] Migrate to the split error-handler API (zenoh-flat-jni #45) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit prebindgen split the generated JNI error callback into two channels: the binding `JniErrorHandler.run(je)` (unchanged) and the typed domain `ErrorHandler.run(message)` (`je` removed, called only on a domain `Err`). A fallible flat wrapper now takes both — `onBindingError` then `onError`. `JNIErrorHandlers.kt`: - `throwZError` becomes the 1-arg domain handler (`ErrorHandler { message -> throw ZError(message) }`). - `throwZError0` (the binding `JniErrorHandler`) is unchanged — it now doubles as the `onBindingError` of a fallible call. Call sites: every fallible flat call gains `throwZError0` before its `throwZError` (42 sites across Config/Session/KeyExpr/Liveliness/Publisher/ Querier/Query/Scout + one jvmTest), matching the wrapper's `(…, onBindingError, onError)` order. Infallible calls (`throwZError0`) and the binding-only `Encoding.newFromId { je -> … }` lambda are untouched. Builds against the local composite zenoh-flat-jni (split-error-handler); 120 jvmTest tests pass, including the domain-error paths (`configFailsWithIllFormatedYAMLTest`, `insertIllFormattedJson5ShouldFailTest`). Co-Authored-By: Claude Opus 4.8 --- .../src/commonMain/kotlin/io/zenoh/Config.kt | 12 ++++----- .../src/commonMain/kotlin/io/zenoh/Session.kt | 26 +++++++++--------- .../io/zenoh/exceptions/JNIErrorHandlers.kt | 27 ++++++++++--------- .../kotlin/io/zenoh/keyexpr/KeyExpr.kt | 14 +++++----- .../kotlin/io/zenoh/liveliness/Liveliness.kt | 15 ++++++----- .../kotlin/io/zenoh/pubsub/Publisher.kt | 5 ++-- .../kotlin/io/zenoh/query/Querier.kt | 5 ++-- .../commonMain/kotlin/io/zenoh/query/Query.kt | 7 ++--- .../kotlin/io/zenoh/scouting/Scout.kt | 3 ++- .../kotlin/io/zenoh/QueryParametersTest.kt | 3 ++- 10 files changed, 62 insertions(+), 55 deletions(-) diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt index d45049d7..5d0e4937 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Config.kt @@ -72,7 +72,7 @@ class Config internal constructor(internal val zConfig: JniConfig) { */ @JvmStatic @Throws(ZError::class) - fun fromFile(path: Path): Config = Config(JniConfig.newFromFile(path.toString(), throwZError)) + fun fromFile(path: Path): Config = Config(JniConfig.newFromFile(path.toString(), throwZError0, throwZError)) /** * Loads the configuration from json-formatted string. @@ -85,7 +85,7 @@ class Config internal constructor(internal val zConfig: JniConfig) { */ @JvmStatic @Throws(ZError::class) - fun fromJson(config: String): Config = Config(JniConfig.newFromJson(config, throwZError)) + fun fromJson(config: String): Config = Config(JniConfig.newFromJson(config, throwZError0, throwZError)) /** * Loads the configuration from json5-formatted string. @@ -98,7 +98,7 @@ class Config internal constructor(internal val zConfig: JniConfig) { */ @JvmStatic @Throws(ZError::class) - fun fromJson5(config: String): Config = Config(JniConfig.newFromJson5(config, throwZError)) + fun fromJson5(config: String): Config = Config(JniConfig.newFromJson5(config, throwZError0, throwZError)) /** * Loads the configuration from yaml-formatted string. @@ -111,7 +111,7 @@ class Config internal constructor(internal val zConfig: JniConfig) { */ @JvmStatic @Throws(ZError::class) - fun fromYaml(config: String): Config = Config(JniConfig.newFromYaml(config, throwZError)) + fun fromYaml(config: String): Config = Config(JniConfig.newFromYaml(config, throwZError0, throwZError)) /** * Loads the configuration from the env variable [CONFIG_ENV]. @@ -134,12 +134,12 @@ class Config internal constructor(internal val zConfig: JniConfig) { * The json value associated to the [key]. */ @Throws(ZError::class) - fun getJson(key: String): String = zConfig.getJson(key, throwZError) + fun getJson(key: String): String = zConfig.getJson(key, throwZError0, throwZError) /** * Inserts a json5 value associated to the [key] into the Config. */ @Throws(ZError::class) fun insertJson5(key: String, value: String) = - zConfig.insertJson5(key, value, throwZError) + zConfig.insertJson5(key, value, throwZError0, throwZError) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt index b28291c2..21fb9f6d 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/Session.kt @@ -399,7 +399,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { // The one place a KeyExpr carries a native handle: the wire // declaration attached here makes sends through this session // compact, so the handle is worth holding. - KeyExpr(keyExpr, zSession.declareKeyexpr(keyExpr, throwZError)) + KeyExpr(keyExpr, zSession.declareKeyexpr(keyExpr, throwZError0, throwZError)) } strongDeclarations.add(keyexpr) return keyexpr @@ -422,7 +422,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { throw ZError("Attempting to undeclare a non declared key expression.") } try { - zSession.undeclareKeyexpr(handle, throwZError) + zSession.undeclareKeyexpr(handle, throwZError0, throwZError) } finally { // The generated wrapper consumes the handle even when the native // undeclare fails (the Rust side takes it by value) — detach it @@ -614,7 +614,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { options.priority.jni, options.express, options.reliability.jni, - throwZError + throwZError0, throwZError ) Publisher( keyExpr, @@ -638,7 +638,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { keyExpr.jniSel, keyExpr.jniStr, keyExpr.cloneHandle(), sampleCallbackOf { handler.handle(it) }, { handler.onClose() }, - throwZError + throwZError0, throwZError ) HandlerSubscriber(keyExpr, zSubscriber, handler.receiver()) } @@ -656,7 +656,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { keyExpr.jniSel, keyExpr.jniStr, keyExpr.cloneHandle(), sampleCallbackOf { callback.run(it) }, { }, - throwZError + throwZError0, throwZError ) CallbackSubscriber(keyExpr, zSubscriber) } @@ -675,7 +675,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { options.complete, queryCallbackOf { handler.handle(it) }, { handler.onClose() }, - throwZError + throwZError0, throwZError ) HandlerQueryable(keyExpr, zQueryable, handler.receiver()) } @@ -694,7 +694,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { options.complete, queryCallbackOf { callback.run(it) }, { }, - throwZError + throwZError0, throwZError ) CallbackQueryable(keyExpr, zQueryable) } @@ -718,7 +718,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { options.express, options.timeout.toMillis(), options.acceptReplies.toFlat(), - throwZError + throwZError0, throwZError ) Querier( keyExpr, @@ -758,7 +758,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { options.attachment?.into()?.bytes, replyCallbackOf { handler.handle(it) }, { handler.onClose() }, - throwZError + throwZError0, throwZError ) handler.receiver() } @@ -788,7 +788,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { options.attachment?.into()?.bytes, replyCallbackOf { callback.run(it) }, { }, - throwZError + throwZError0, throwZError ) } } @@ -807,7 +807,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { putOptions.express, putOptions.attachment?.into()?.bytes, putOptions.reliability.jni, - throwZError + throwZError0, throwZError ) } } @@ -823,7 +823,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { deleteOptions.express, deleteOptions.attachment?.into()?.bytes, deleteOptions.reliability.jni, - throwZError + throwZError0, throwZError ) } } @@ -853,7 +853,7 @@ class Session private constructor(private val config: Config) : AutoCloseable { private fun launch(): Session { this.zSession = io.zenoh.jni.session.Session.open( config.zConfig.newClone(throwZError0), - throwZError, + throwZError0, throwZError, ) return this } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/JNIErrorHandlers.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/JNIErrorHandlers.kt index d4a6954e..94143dec 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/JNIErrorHandlers.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/exceptions/JNIErrorHandlers.kt @@ -20,23 +20,24 @@ import io.zenoh.jni.errors.ErrorHandler /** * Error-callback handlers passed to the generated flat-jni wrappers. In the * canonical model a wrapper never throws from native code — on failure it - * invokes its trailing `onError` handler (a generated typed `fun interface`). - * These handlers throw [ZError] directly, so the SDK no longer needs a - * `try/catch` translation layer. + * invokes an error handler (a generated typed `fun interface`). These handlers + * throw [ZError] directly, so the SDK no longer needs a `try/catch` layer. * - * `je` is the binding-layer error (UTF-8 decode, closed handle, …); `ze` is the - * library (zenoh) error message. Exactly one is set. The handlers bind the - * interface's `out R` to [Nothing], which is a subtype of every `R`, so a - * single instance satisfies every wrapper's `onError` regardless of its - * return type (declaration-site covariance). + * The generated protocol has two independent channels (prebindgen #45): a + * fallible wrapper takes `onBindingError` (a [JniErrorHandler], any + * binding-layer failure — UTF-8 decode, closed handle, …) followed by + * `onError` (the typed domain [ErrorHandler], the decomposed zenoh error); + * an infallible wrapper takes only the binding [JniErrorHandler]. The handlers + * bind the interface's `out R` to [Nothing], a subtype of every `R`, so a + * single instance satisfies every wrapper regardless of its return type + * (declaration-site covariance). */ -/** Handler for a fallible wrapper (`Result<_, ZError>`): `run(je, message)`. - * `message` is builder-typed (non-null) — on a binding error (`je != null`) - * the native side fills it with the default `""`. */ +/** Domain handler for a fallible wrapper (`Result<_, ZError>`): `run(message)`. */ internal val throwZError: ErrorHandler = - ErrorHandler { je, message -> throw ZError(je ?: message) } + ErrorHandler { message -> throw ZError(message) } -/** Handler for an infallible wrapper (binding errors only): `run(je)`. */ +/** Binding handler — the `onBindingError` of a fallible wrapper AND the sole + * `onError` of an infallible one: `run(je)`. */ internal val throwZError0: JniErrorHandler = JniErrorHandler { je -> throw ZError(je ?: "native binding error") } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt index f8846b05..ae79b6a4 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/keyexpr/KeyExpr.kt @@ -81,7 +81,7 @@ class KeyExpr internal constructor( private inline fun withHandle(body: (JniKeyExpr) -> R): R { val h = handle if (h != null) return body(h) - val tmp = JniKeyExpr.newTryFrom(keyExprString, throwZError) + val tmp = JniKeyExpr.newTryFrom(keyExprString, throwZError0, throwZError) try { return body(tmp) } finally { @@ -110,7 +110,7 @@ class KeyExpr internal constructor( @JvmStatic @Throws(ZError::class) fun tryFrom(keyExpr: String): KeyExpr { - JniKeyExpr.newTryFrom(keyExpr, throwZError).close() + JniKeyExpr.newTryFrom(keyExpr, throwZError0, throwZError).close() return KeyExpr(keyExpr) } @@ -127,7 +127,7 @@ class KeyExpr internal constructor( @JvmStatic @Throws(ZError::class) fun autocanonize(keyExpr: String): KeyExpr { - val probe = JniKeyExpr.newAutocanonize(keyExpr, throwZError) + val probe = JniKeyExpr.newAutocanonize(keyExpr, throwZError0, throwZError) try { return KeyExpr(probe.getStr(throwZError0)) } finally { @@ -178,8 +178,8 @@ class KeyExpr internal constructor( fun join(other: String): KeyExpr { // The companion factory validates and joins natively; the result is a // fresh (declaration-less) handle — keep its canonical string only. - val probe = handle?.let { JniKeyExpr.newJoin(it, other, throwZError) } - ?: JniKeyExpr.newJoin(keyExprString, other, throwZError) + val probe = handle?.let { JniKeyExpr.newJoin(it, other, throwZError0, throwZError) } + ?: JniKeyExpr.newJoin(keyExprString, other, throwZError0, throwZError) try { return KeyExpr(probe.getStr(throwZError0)) } finally { @@ -193,8 +193,8 @@ class KeyExpr internal constructor( */ @Throws(ZError::class) fun concat(other: String): KeyExpr { - val probe = handle?.let { JniKeyExpr.newConcat(it, other, throwZError) } - ?: JniKeyExpr.newConcat(keyExprString, other, throwZError) + val probe = handle?.let { JniKeyExpr.newConcat(it, other, throwZError0, throwZError) } + ?: JniKeyExpr.newConcat(keyExprString, other, throwZError0, throwZError) try { return KeyExpr(probe.getStr(throwZError0)) } finally { diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt index 15205f20..9fee07c9 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/liveliness/Liveliness.kt @@ -19,6 +19,7 @@ import io.zenoh.replyCallbackOf import io.zenoh.sampleCallbackOf import io.zenoh.exceptions.ZError import io.zenoh.exceptions.throwZError +import io.zenoh.exceptions.throwZError0 import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Callback import io.zenoh.handlers.Handler @@ -54,7 +55,7 @@ class Liveliness internal constructor(private val session: Session) { @Throws(ZError::class) fun declareToken(keyExpr: KeyExpr): LivelinessToken { val zSession = session.zSession ?: throw Session.sessionClosedException - return LivelinessToken(zSession.livelinessDeclareToken(keyExpr.jniSel, keyExpr.jniStr, keyExpr.cloneHandle(), throwZError)) + return LivelinessToken(zSession.livelinessDeclareToken(keyExpr.jniSel, keyExpr.jniStr, keyExpr.cloneHandle(), throwZError0, throwZError)) } /** @@ -76,7 +77,7 @@ class Liveliness internal constructor(private val session: Session) { timeout.toMillis(), replyCallbackOf { handler.handle(it) }, { handler.onClose() }, - throwZError + throwZError0, throwZError ) return handler.receiver() } @@ -99,7 +100,7 @@ class Liveliness internal constructor(private val session: Session) { timeout.toMillis(), replyCallbackOf { callback.run(it) }, { }, - throwZError + throwZError0, throwZError ) } @@ -122,7 +123,7 @@ class Liveliness internal constructor(private val session: Session) { timeout.toMillis(), replyCallbackOf { handler.handle(it) }, { handler.onClose() }, - throwZError + throwZError0, throwZError ) return handler.receiver() } @@ -146,7 +147,7 @@ class Liveliness internal constructor(private val session: Session) { options.history, sampleCallbackOf { handler.handle(it) }, { handler.onClose() }, - throwZError + throwZError0, throwZError ) return HandlerSubscriber(keyExpr, zSubscriber, handler.receiver()) } @@ -171,7 +172,7 @@ class Liveliness internal constructor(private val session: Session) { options.history, sampleCallbackOf { callback.run(it) }, { }, - throwZError + throwZError0, throwZError ) return CallbackSubscriber(keyExpr, zSubscriber) } @@ -197,7 +198,7 @@ class Liveliness internal constructor(private val session: Session) { options.history, sampleCallbackOf { handler.handle(it) }, { handler.onClose() }, - throwZError + throwZError0, throwZError ) return HandlerSubscriber(keyExpr, zSubscriber, handler.receiver()) } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt index c1400660..6837e2dd 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/pubsub/Publisher.kt @@ -24,6 +24,7 @@ import io.zenoh.bytes.IntoZBytes import io.zenoh.bytes.ZBytes import io.zenoh.exceptions.ZError import io.zenoh.exceptions.throwZError +import io.zenoh.exceptions.throwZError0 import io.zenoh.jni.pubsub.Publisher as JniPublisher import io.zenoh.keyexpr.KeyExpr import io.zenoh.qos.CongestionControl @@ -112,7 +113,7 @@ class Publisher internal constructor( @Throws(ZError::class) fun delete(options: DeleteOptions = DeleteOptions()) { val p = zPublisher ?: throw publisherNotValid - p.delete(options.attachment?.into()?.bytes, throwZError) + p.delete(options.attachment?.into()?.bytes, throwZError0, throwZError) } /** @@ -142,7 +143,7 @@ class Publisher internal constructor( payload.into().bytes, encoding.jniSel, encoding.jniId, encoding.jniSchema, encoding.jniHandle, attachment?.into()?.bytes, - throwZError, + throwZError0, throwZError, ) } } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt index aa51663f..10e68e5a 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Querier.kt @@ -25,6 +25,7 @@ import io.zenoh.bytes.IntoZBytes import io.zenoh.bytes.ZBytes import io.zenoh.exceptions.ZError import io.zenoh.exceptions.throwZError +import io.zenoh.exceptions.throwZError0 import io.zenoh.handlers.BlockingQueueHandler import io.zenoh.handlers.Callback import io.zenoh.handlers.Handler @@ -154,7 +155,7 @@ class Querier internal constructor(val keyExpr: KeyExpr, val qos: QoS, private v options.attachment?.into()?.bytes, replyCallbackOf { callback.run(it) }, { }, - throwZError + throwZError0, throwZError ) } @@ -167,7 +168,7 @@ class Querier internal constructor(val keyExpr: KeyExpr, val qos: QoS, private v options.attachment?.into()?.bytes, replyCallbackOf { handler.handle(it) }, { handler.onClose() }, - throwZError + throwZError0, throwZError ) return handler.receiver() } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt index 14132c2e..583f4eb6 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/query/Query.kt @@ -24,6 +24,7 @@ import io.zenoh.bytes.IntoZBytes import io.zenoh.bytes.ZBytes import io.zenoh.exceptions.ZError import io.zenoh.exceptions.throwZError +import io.zenoh.exceptions.throwZError0 import io.zenoh.keyexpr.KeyExpr import io.zenoh.keyexpr.jniSel import io.zenoh.keyexpr.jniStr @@ -110,7 +111,7 @@ class Query internal constructor( options.timeStamp?.ntpValue(), options.attachment?.into()?.bytes, options.express, - throwZError + throwZError0, throwZError ) // Single-reply model: dropping the native query finalizes the reply // stream so the querier's get completes. Safe whether the query came @@ -147,7 +148,7 @@ class Query internal constructor( options.timeStamp?.ntpValue(), options.attachment?.into()?.bytes, options.express, - throwZError + throwZError0, throwZError ) q.close() zQuery = null @@ -164,7 +165,7 @@ class Query internal constructor( fun replyErr(message: IntoZBytes, options: ReplyErrOptions = ReplyErrOptions()) { val q = zQuery ?: throw ZError("Query is invalid") val enc = options.encoding - q.replyError(message.into().bytes, enc.jniSel, enc.jniId, enc.jniSchema, enc.jniHandle, throwZError) + q.replyError(message.into().bytes, enc.jniSel, enc.jniId, enc.jniSchema, enc.jniHandle, throwZError0, throwZError) q.close() zQuery = null } diff --git a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt index fb7af94b..dc2262b7 100644 --- a/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt +++ b/zenoh-java/src/commonMain/kotlin/io/zenoh/scouting/Scout.kt @@ -19,6 +19,7 @@ import io.zenoh.config.WhatAmI import io.zenoh.config.ZenohId import io.zenoh.exceptions.ZError import io.zenoh.exceptions.throwZError +import io.zenoh.exceptions.throwZError0 import io.zenoh.handlers.Callback /** @@ -98,7 +99,7 @@ sealed class Scout ( val bitfield = whatAmI.map { it.jni.value }.reduce { acc, v -> acc or v } val helloCallback = io.zenoh.helloCallbackOf { callback.run(it) } val onCloseCallback = { onClose() } - return io.zenoh.jni.scouting.scout(bitfield, config?.zConfig, helloCallback, onCloseCallback, throwZError) + return io.zenoh.jni.scouting.scout(bitfield, config?.zConfig, helloCallback, onCloseCallback, throwZError0, throwZError) } } diff --git a/zenoh-java/src/jvmTest/kotlin/io/zenoh/QueryParametersTest.kt b/zenoh-java/src/jvmTest/kotlin/io/zenoh/QueryParametersTest.kt index ffd3b180..d6e520bd 100644 --- a/zenoh-java/src/jvmTest/kotlin/io/zenoh/QueryParametersTest.kt +++ b/zenoh-java/src/jvmTest/kotlin/io/zenoh/QueryParametersTest.kt @@ -15,6 +15,7 @@ package io.zenoh import io.zenoh.exceptions.throwZError +import io.zenoh.exceptions.throwZError0 import io.zenoh.keyexpr.KeyExpr import io.zenoh.query.Parameters import io.zenoh.query.Query @@ -91,7 +92,7 @@ class QueryParametersTest { null, // attachment replyCallbackOf { reply = it }, {}, // onClose - throwZError, + throwZError0, throwZError, ) Thread.sleep(1000) From 45d87876756a2caa9575fc594f1f760ae46a9f80 Mon Sep 17 00:00:00 2001 From: Michael Ilyin Date: Tue, 21 Jul 2026 13:10:04 +0200 Subject: [PATCH 2/2] ci: repoint zenoh-flat-jni pin to the split regen + ownership marker The split error-handler regeneration (zenoh-flat-jni #10) plus the merged Kotlin ownership-marker fix (zenoh-flat-jni #11, 249fe9e on shared-parameters). CI pinned the pre-split 757cc6a, whose single-channel `ErrorHandler.run(je, message)` wrappers are incompatible with this branch's two-caller call sites; #11's marker is also required for the composite `cargo build` to regenerate at all (write_kotlin refuses a non-empty output root without it). Point CI at the merged commit so the composite build both matches the source and regenerates. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef4e60f8..a3265d3f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: uses: actions/checkout@v4 with: repository: ZettaScaleLabs/zenoh-flat-jni - ref: 757cc6ad7e346f428ffc5e3252ba01ff4d19ba9b + ref: 249fe9e34ac5d05bc442355fd216a324114e2621 path: zenoh-flat-jni - name: Check out zenoh-flat