risingwavelabs/risingwave · error · SinkError::Iceberg
partition_spec_id should be a u64
Error message
partition_spec_id should be a u64
What it means
In try_from_serialized_bytes, the 'partition_spec_id' JSON field is matched as serde_json::Value::Number, then narrowed with as_u64(). If the value is a JSON number that is not representable as u64 (negative or fractional), this error fires. It enforces that partition_spec_id is a non-negative integer before it is cast to i32.
Source
Thrown at src/connector/src/sink/iceberg/commit.rs:93
value
} else {
bail!("iceberg sink metadata should be an object");
};
let schema_id;
if let Some(serde_json::Value::Number(value)) = values.remove(SCHEMA_ID) {
schema_id = value
.as_u64()
.ok_or_else(|| anyhow!("schema_id should be a u64"))?;
} else {
bail!("iceberg sink metadata should have schema_id");
}
let partition_spec_id;
if let Some(serde_json::Value::Number(value)) = values.remove(PARTITION_SPEC_ID) {
partition_spec_id = value
.as_u64()
.ok_or_else(|| anyhow!("partition_spec_id should be a u64"))?;
} else {
bail!("iceberg sink metadata should have partition_spec_id");
}
let data_files: Vec<SerializedDataFile>;
if let serde_json::Value::Array(values) = values
.remove(DATA_FILES)
.ok_or_else(|| anyhow!("iceberg sink metadata should have data_files object"))?
{
data_files = values
.into_iter()
.map(from_value::<SerializedDataFile>)
.collect::<std::result::Result<_, _>>()
.unwrap();
} else {
bail!("iceberg sink metadata should have data_files object");
}
View on GitHub (pinned to 6469eb736d)
Solutions
- Fix the metadata producer so partition_spec_id is serialized via serde_json::Value::Number from a i32/u32 value
- Validate the raw JSON: partition_spec_id must be an integer >= 0 and <= i32::MAX (it is cast to i32 afterwards)
- Replace the corrupted metadata entry with a freshly produced write result
Example fix
// before
{"schema_id":1,"partition_spec_id":-1,"data_files":[]}
// after
{"schema_id":1,"partition_spec_id":0,"data_files":[]} Defensive patterns
Strategy: validation
Validate before calling
fn valid_partition_spec_id(bytes: &[u8]) -> bool {
serde_json::from_slice::<serde_json::Value>(bytes).ok()
.and_then(|v| v.get("partition_spec_id").cloned())
.map_or(false, |v| v.as_u64().map_or(false, |n| n <= i32::MAX as u64))
} Type guard
fn as_nonneg_int(v: &serde_json::Value, key: &str) -> Option<i64> {
v.get(key)?.as_i64().filter(|n| *n >= 0)
} Try / catch
match try_from_serialized_bytes(&bytes) {
Ok(r) => r,
Err(e) => return Err(SinkError::Iceberg(anyhow!("invalid metadata: {}", e.as_report()))),
} Prevention
- Never hand-edit sink metadata JSON
- Serialize ids from integer types, not floats or strings
- Validate metadata shape in tests with round-trip serialize/deserialize
When it happens
Trigger: Metadata JSON where 'partition_spec_id' is a negative integer (e.g. -1) or a float (e.g. 0.5); happens when metadata was produced by non-standard code or manually edited.
Common situations: Manually patched metadata in a debugging session, third-party tooling writing Iceberg sink metadata, corrupt values after storage truncation.
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
- schema_id should be a u64
- Join key types are not aligned: LHS: {outer_type:?}, RHS: {i
- Join key types are not aligned: LHS: {outer_type:?}, RHS: {i
- unsupported JSON number: {v}
- table {} not found
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/c6cda8881e1a1132.
Report an issue: GitHub.