risingwavelabs/risingwave · error · ValueEncodingError

Invalid null tag value encoding: {0}

Error message

Invalid null tag value encoding: {0}

What it means

`ValueEncodingError::InvalidTagEncoding` is raised when decoding a nullable value-encoded datum: each encoded value starts with a one-byte null tag, and only 0 (null) and 1 (non-null) are valid. Any other byte means the buffer is not a well-formed value-encoded nullable datum or the reader is misaligned.

Source

Thrown at src/common/src/util/value_encoding/error.rs:29

// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use thiserror::Error;

#[derive(Error, Debug)]
pub enum ValueEncodingError {
    #[error("Invalid bool value encoding: {0}")]
    InvalidBoolEncoding(u8),
    #[error("Invalid UTF8 value encoding: {0}")]
    InvalidUtf8(#[from] std::string::FromUtf8Error),
    #[error("Invalid Date value encoding: days: {0}")]
    InvalidDateEncoding(i32),
    #[error("invalid Timestamp value encoding: secs: {0} nsecs: {1}")]
    InvalidTimestampEncoding(i64, u32),
    #[error("invalid Time value encoding: secs: {0} nano: {1}")]
    InvalidTimeEncoding(u32, u32),
    #[error("Invalid null tag value encoding: {0}")]
    InvalidTagEncoding(u8),
    #[error("Invalid jsonb encoding")]
    InvalidJsonbEncoding,
    #[error("Invalid variant encoding")]
    InvalidVariantEncoding,
    #[error("Invalid struct encoding: {0}")]
    InvalidStructEncoding(
        #[source]
        #[backtrace]
        crate::array::ArrayError,
    ),
    #[error("Invalid list encoding: {0}")]
    InvalidListEncoding(
        #[source]
        #[backtrace]
        crate::array::ArrayError,
    ),
    #[error("Invalid flag: {0:b}")]

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Check the offending tag byte in the message; ensure nullable values are encoded with tag 0 (null) or 1 (value)
  2. Verify the decode offset — the tag byte must be the first byte of each datum
  3. Ensure the producer used RisingWave's value-encoding Option encoder rather than a custom format
  4. Re-produce or resync the corrupted data source

Example fix

// before
let mut buf = vec![2u8]; // invalid null tag
buf.extend_from_slice(&42i32.to_be_bytes());
// after
let mut buf = vec![1u8]; // 1 = present, 0 = null
buf.extend_from_slice(&42i32.to_be_bytes());
Defensive patterns

Strategy: try-catch

Validate before calling

// check the leading null tag before decoding an optional datum
fn is_valid_null_tag(bytes: &[u8]) -> bool {
    matches!(bytes.first(), Some(0) | Some(1))
}

Type guard

fn null_tag(b: u8) -> Option<bool> { match b { 0 => Some(false), 1 => Some(true), _ => None } }

Try / catch

match Option::<i32>::try_from_value_encoding(bytes) {
    Ok(v) => v,
    Err(ValueEncodingError::InvalidTagEncoding(tag)) => {
        // treat as corrupt: skip record or fail the pipeline
        return Err(anyhow!("invalid null tag {tag}"));
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Decoding an optional/nullable column whose leading byte is not 0 or 1 — reading at a wrong offset, decoding a non-value-encoded buffer, or hand-written encoders writing other tag bytes (e.g. 0xFF).

Common situations: Corrupted or truncated serialized data, version/format skew between producers and consumers, manual construction of value-encoded bytes with wrong tag conventions, misaligned row slicing.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/35407e38eeca41ed. Report an issue: GitHub.