databendlabs/databend · error
Invalid temp table desc
Error message
Invalid temp table desc: {} What it means
Temp table descriptors are encoded as `"<db_name>.<table_name>"` where each name part is wrapped in quotes, e.g. `"db"."tbl"`. `TxnBuffer::parse_db_tbl_name` panics when the descriptor contains no `.` separator, meaning the desc string is malformed or was produced by a different code path/version.
Solutions
- Inspect the malformed desc value and fix the producer so it emits the quoted `"db"."table"` format.
- Add a validation step before registering temp tables so unquoted or dot-less names are rejected at the API boundary with a proper error instead of a panic.
- Check for version skew: if the desc came from persisted state written by an older release, migrate or re-create the affected temp tables.
Example fix
// before: silent panic on malformed desc
let (db_raw, table_raw) = desc.split_once('.')
.unwrap_or_else(|| panic!("Invalid temp table desc: {}", desc));
// after: return a typed error
let (db_raw, table_raw) = desc.split_once('.')
.ok_or_else(|| ErrorCode::BadArguments(format!("Invalid temp table desc: {desc}")))?; Defensive patterns
Strategy: validation
Validate before calling
// Validate the temp table desc before handing it to TxnBuffer
fn is_valid_temp_table_desc(desc: &str) -> bool {
let parts: Vec<&str> = desc.split('.').collect();
parts.len() == 2 && parts[0].len() >= 2 && parts[1].len() >= 2
} Try / catch
// Catch panics from parsing untrusted descs in batch processing
let result = std::panic::catch_unwind(|| txn_buffer.parse_and_apply(desc));
match result {
Ok(res) => res?,
Err(_) => return Err(format!("Invalid temp table desc: {desc}")),
} Prevention
- Always build temp table descs via the quoting helper (quoted db and table joined by a dot).
- Reject unquoted or dot-less table names at the API boundary.
- Never feed externally supplied strings directly as temp table descriptors.
- Add a round-trip unit test: format desc, parse it back, compare.
When it happens
Trigger: Calling any `TxnBuffer` operation (append/commit/clear paths) with a temp-table desc that lacks a dot, e.g. a bare table name `mytable` instead of `"mydb"."mytable"`, or an empty desc string.
Common situations: Hand-crafted or externally supplied temp table descriptors, version skew between nodes writing descs in an older format, or corruption of serialized transaction buffers containing temp table entries.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/9b3992d966f8a96f.
Report an issue: GitHub.
Appendix: source
Thrown at src/query/storages/common/session/src/transaction.rs:100
// TODO doc this
table_tnx_begin_timestamps: HashMap<u64, DateTime<Utc>>,
temp_table_desc_to_id: HashMap<String, u64>,
mutated_temp_tables: HashMap<u64, TempTable>,
}
#[derive(Debug, Clone)]
pub struct StreamSnapshot {
pub stream: TableInfo,
pub source: TableInfo,
pub max_batch_size: Option<u64>,
}
impl TxnBuffer {
fn parse_db_tbl_name(desc: &str) -> (String, String) {
let (db_raw, table_raw) = desc
.split_once('.')
.unwrap_or_else(|| panic!("Invalid temp table desc: {}", desc));
let db_name = db_raw[1..db_raw.len() - 1].to_string();
let table_name = table_raw[1..table_raw.len() - 1].to_string();
(db_name, table_name)
}
fn clear(&mut self) {
std::mem::take(self);
}
fn update_multi_table_meta(
&mut self,
tenant: &Tenant,
mut req: UpdateMultiTableMetaReq,
) -> Result<()> {
// Bind the transaction to the first non-conflicting tenant that updates meta.
// Later updates must stay on the same tenant; commit uses this bound value.
match &self.tenant {
None => self.tenant = Some(tenant.clone()),View on GitHub (pinned to 288d84d76e)