databendlabs/databend · error
Operation::AsIs is not supported
Error message
Operation::AsIs is not supported
What it means
encode_operation converts a typed Operation<T> into its protobuf-encoded Operation<Vec<u8>>, and it only supports Update and Delete. Operation::AsIs (a directive meaning 'leave the existing value untouched') cannot be encoded into a value-carrying upsert, so reaching the match wildcard panics. The API contract is that callers must only pass Update or Delete to this encoder.
Solutions
- Do not pass Operation::AsIs to encode_operation; handle AsIs at the caller level (skip the write or resolve it to an explicit value first)
- Match on the operation before encoding: return Operation::AsIs passthrough or an error for unsupported variants
- If you need AsIs semantics, use a transaction API that natively supports the AsIs operation instead of the pb encoder
- Audit call sites of encode_operation and add debug asserts/tests that reject AsIs early
Example fix
// before
let encoded = sm.encode_operation(&op); // panics if op == AsIs
// after
let encoded = match op {
Operation::Update(_) | Operation::Delete => sm.encode_operation(&op),
Operation::AsIs => return Err(ErrorCode::InternalError("AsIs not encodable")),
}; Defensive patterns
Strategy: type-guard
Validate before calling
if matches!(op, Operation::AsIs) { return Err(ErrorCode::InternalError("AsIs not supported by encode_operation")); } Type guard
fn is_encodable<T>(op: &Operation<T>) -> bool { !matches!(op, Operation::AsIs) } Try / catch
// not a catchable error: it panics. Guard instead: assert!(!matches!(op, Operation::AsIs), "AsIs must be resolved before encoding");
Prevention
- Resolve Operation::AsIs to a concrete value before calling pb encoders
- Add unit tests asserting encode_operation rejects/handles AsIs
- Use txn APIs that natively support AsIs when needed
When it happens
Trigger: Calling encode_operation (directly or via an upsert/SafeUpload path) with an Operation that is Operation::AsIs — e.g. generic meta write code that copies a caller-supplied Operation without normalizing AsIs first.
Common situations: New meta API code reusing encode_operation with share/AsIs-style semantics; refactors that forward Operations from higher layers without filtering; misuse of the pb_api by extension code.
Related errors
- internal error: expect TxnGetResponseGet of get database…
- Unsupported format for
- Unsupported source type. Expected path, pandas.DataFrame…
- Access denied: is outside allowed directories
- rename_database: src (db) should exist
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/44a7cdc18c2f4161.
Report an issue: GitHub.
Appendix: source
Thrown at src/meta/api/src/kv/pb_api/compress.rs:68
impl Encoder {
pub const fn new(compress: bool) -> Self {
Self {
compress: AtomicBool::new(compress),
}
}
pub fn set_compress(&self, compress: bool) {
self.compress.store(compress, Ordering::Relaxed);
}
/// Encode an upsert Operation of T into protobuf encoded value.
pub fn encode_operation<T: FromToProto>(&self, value: &Operation<T>) -> Operation<Vec<u8>> {
match value {
Operation::Update(t) => Operation::Update(self.encode_pb(t)),
Operation::Delete => Operation::Delete,
_ => {
unreachable!("Operation::AsIs is not supported")
}
}
}
/// Encode a `FromToProto` value to protobuf bytes, with optional zstd compression.
pub fn encode_pb<T: FromToProto>(&self, value: &T) -> Vec<u8> {
let p = value.to_pb();
self.encode_value(prost::Message::encode_to_vec(&p))
}
/// Optionally compress `buf` with zstd.
///
/// Returns `buf` unchanged if compression is disabled or `buf.len() < COMPRESS_THRESHOLD`.
/// Otherwise prepends `[0x0F, FLAG_ZSTD, 0x00, 0x00]` and returns the compressed payload.
/// Falls back to returning `buf` uncompressed on compression error.
pub fn encode_value(&self, buf: Vec<u8>) -> Vec<u8> {
if !self.compress.load(Ordering::Relaxed) {
return buf;View on GitHub (pinned to 288d84d76e)