risingwavelabs/risingwave · error
failed to decode persisted `DefaultColumnDesc`
Error message
failed to decode persisted `DefaultColumnDesc`
What it means
`bind_sql_column_constraints` found a persisted `DEFAULT INTERNAL` column default encoded as protobuf bytes, but `DefaultColumnDesc::decode` failed, so the `expect` panics. The stored bytes no longer parse as a valid `DefaultColumnDesc` — a corrupted or format-mismatched catalog entry.
Solutions
- Recreate the table/source so the default column descriptor is re-encoded with the current format.
- Check version compatibility between the meta store data and the running binary; complete any pending upgrade migration.
- If a test/fixture wrote raw bytes, generate them via `DefaultColumnDesc` protobuf encode instead of hand-crafting.
Example fix
// before: hand-written bytes that don't decode
let persisted: Bytes = Bytes::from_static(b"garbage");
// after: encode a real descriptor
let persisted = DefaultColumnDesc { column_id: 1 }.encode_to_vec().into(); Defensive patterns
Strategy: type-guard
Validate before calling
if let Some(persisted) = default_bytes {
match DefaultColumnDesc::decode(&**persisted) {
Ok(desc) => { /* proceed */ }
Err(e) => return Err(anyhow!("corrupt DefaultColumnDesc in catalog: {}", e)),
}
} Type guard
fn decodable_default(b: &[u8]) -> Option<DefaultColumnDesc> { DefaultColumnDesc::decode(b).ok() } Try / catch
match DefaultColumnDesc::decode(&**persisted) {
Ok(desc) => apply(desc),
Err(e) => log::error!("failed to decode DefaultColumnDesc: {e}"),
} Prevention
- Keep meta-store and binary versions aligned; finish upgrade migrations
- Encode fixture bytes via the proto struct, never by hand
- Back up and validate catalog state before version rollbacks
When it happens
Trigger: CREATE TABLE/SOURCE (via `bind_create_source_or_table_with_connector`, `gen_create_table_plan_without_source`, `gen_create_table_plan_for_cdc_table`) reading a column whose `generated_or_default_column` holds protobuf bytes that fail protobuf decoding — e.g. bytes written by an incompatible older schema version or manually corrupted meta storage.
Common situations: Rolling upgrades where the persisted proto definition changed; restoring state from backups of a different version; meta-store corruption.
Understand the failure class
Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- AZBLOB_ENDPOINT not found from environment variables
- BatchPosixFsReader should not hit this branch. refer to…
- below watermark check condition eval must return bool array
- Can't find
- Can't find message proto
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/4b5cc8caea9fd8e9.
Report an issue: GitHub.
Appendix: source
Thrown at src/frontend/src/handler/create_table.rs:353
column.name
))
.into());
}
}
ColumnOption::DefaultValueInternal { persisted, expr: _ } => {
// When a `DEFAULT INTERNAL` is used internally for schema change, the persisted value
// should already be set during purifcation. So if we encounter an empty value here, it
// means the user has specified it explicitly in the SQL statement, typically by
// directly copying the result of `SHOW CREATE TABLE` and executing it.
if persisted.is_empty() {
bail_bind_error!(
"DEFAULT INTERNAL is only used for internal purposes, \
please specify a concrete default value"
);
}
let desc = DefaultColumnDesc::decode(&**persisted)
.expect("failed to decode persisted `DefaultColumnDesc`");
column_catalogs[idx].column_desc.generated_or_default_column =
Some(GeneratedOrDefaultColumn::DefaultColumn(desc));
}
_ => {}
}
}
}
Ok(())
}
/// Currently we only support Primary key table constraint, so just return pk names if it exists
pub fn bind_table_constraints(table_constraints: &[TableConstraint]) -> Result<Vec<String>> {
let mut pk_column_names = vec![];
for constraint in table_constraints {
match constraint {
TableConstraint::Unique {View on GitHub (pinned to 6469eb736d)