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

  1. Inspect the malformed desc value and fix the producer so it emits the quoted `"db"."table"` format.
  2. 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.
  3. 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

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)