{"record":{"id":"9a9e59154f97818c","repo":"risingwavelabs/risingwave","slug":"decodeerror-error","errorCode":null,"errorMessage":"DecodeError {error}","messagePattern":"DecodeError (.+?)","errorType":"exception","errorClass":"BindingError::Decode","httpStatus":null,"severity":"error","filePath":"src/jni_core/src/lib.rs","lineNumber":98,"sourceCode":"    LazyLock::new(|| tokio::runtime::Runtime::new().unwrap());\n\n#[derive(Error, Debug)]\npub enum BindingError {\n    #[error(\"JniError {error}\")]\n    Jni {\n        #[from]\n        error: jni::errors::Error,\n        backtrace: Backtrace,\n    },\n\n    #[error(\"StorageError {error}\")]\n    Storage {\n        #[from]\n        error: anyhow::Error,\n        backtrace: Backtrace,\n    },\n\n    #[error(\"DecodeError {error}\")]\n    Decode {\n        #[from]\n        error: DecodeError,\n        backtrace: Backtrace,\n    },\n\n    #[error(\"StreamChunkArrayError {error}\")]\n    StreamChunkArray {\n        #[from]\n        error: ArrayError,\n        backtrace: Backtrace,\n    },\n}\n\ntype Result<T> = std::result::Result<T, BindingError>;\n\npub fn to_guarded_slice<'array, 'env>(\n    array: &'array JByteArray<'env>,","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/jni_core/src/lib.rs#L80-L116","documentation":"BindingError::Decode wraps a prost/prost-derived DecodeError produced while decoding protobuf bytes passed from Java into RisingWave internal messages (e.g. StreamChunk, rows, Watch response payloads). Shown as 'DecodeError {error}'. It means the byte payload crossing the JNI boundary is not a valid encoding of the expected protobuf message.","triggerScenarios":"Calling JNI entry points that accept serialized protobuf payloads (byte[] containing StreamChunk, row encodings, etc.) where the bytes are truncated, corrupted, produced by a different schema version, or not protobuf at all.","commonSituations":"Java client built against an older protobuf schema than the native library (version skew); passing compressed or base64 text where raw protobuf bytes are expected; manually assembled byte arrays with wrong field ordering.","solutions":["Verify the Java side serializes with the exact same generated protobuf class/version as the native binding was built with","Dump the failing byte[] length and first bytes to confirm it is the expected wire format (not base64/compressed text)","Regenerate the Java protobuf stubs from the same .proto files used to build risingwave_jni_core","If version skew is expected, pin both the JAR and native library to the same RisingWave release"],"exampleFix":"// before\nbyte[] bytes = Base64.decode(payload); // DecodeError: invalid wire type\nbinding.next(bytes);\n// after\nbyte[] bytes = payload.toByteArray(); // raw protobuf bytes from matching generated class\nbinding.next(bytes);","handlingStrategy":"validation","validationCode":"// Java, before crossing the boundary\nbyte[] bytes = protoMsg.toByteArray(); // never base64/compressed text\nif (bytes.length == 0) throw new IllegalStateException(\"empty protobuf payload\");","typeGuard":null,"tryCatchPattern":"try {\n    binding.decode(bytes);\n} catch (RuntimeException e) {\n    if (e.getMessage().contains(\"DecodeError\")) {\n        // schema/version skew: regenerate stubs, verify byte source\n    }\n    throw e;\n}","preventionTips":["Generate Java protobuf stubs from the same .proto revision as the native lib","Pass raw protobuf bytes only — no base64/compression wrappers","Pin RisingWave JAR and native library to the same release","Sanity-check payload size/first bytes when debugging"],"tags":["protobuf","decode","jni","serialization"],"backgroundTag":"protobuf-unmarshal-failed","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}