databendlabs/databend · error

internal error: entered unreachable code

Error message

internal error: entered unreachable code

What it means

`unreachable!()` in `SessionCatalog::retryable_update_multi_table_meta` (session_catalog.rs): after replaying/committing a multi-table transaction, the code matches the transaction state and asserts `TxnState::Fail` is impossible on this path — a failed txn is expected to be retried or surfaced as an error earlier. Hitting it means the transaction manager returned a Fail state where only Committed/Active were expected, i.e. transaction state-machine corruption or a missing retry branch.

Solutions

  1. Roll back / abort the failed transaction before issuing further metadata updates (ROLLBACK, or start a new transaction).
  2. Check prior errors in the session — the Fail state usually stems from an earlier failed statement that must be handled, not retried.
  3. Upgrade Databend; ensure `retryable_update_multi_table_meta` converts `TxnState::Fail` into a proper error instead of panicking.
  4. Inspect transaction-manager logs and file an issue with the DDL sequence if the state appears inconsistent.

Example fix

// before
TxnState::Fail => unreachable!(),
// after
TxnState::Fail => Err(ErrorCode::TxnFailed(
    "cannot retry update_multi_table_meta on failed transaction; abort and retry the transaction",
)),
Defensive patterns

Strategy: try-catch

Validate before calling

// application-side: only issue metadata DDL while the txn state is Active
if txn_state() != TxnState::Active { abort_and_restart_txn(); }

Try / catch

// treat TxnState::Fail surfaced as unreachable panic as a txn-abort requirement
match exec(ddl) {
    Err(e) if e.to_string().contains("entered unreachable code") => { rollback(); retry_txn(); }
    other => other,
}

Prevention

When it happens

Trigger: Calling DDL/metadata operations (`update_multi_table_meta`) inside an explicit transaction whose state is `TxnState::Fail` — e.g. after a prior statement in the transaction failed but the session retried the metadata update without aborting/rolling back the failed transaction.

Common situations: Multi-statement transactions where one statement errored and a subsequent metadata update is retried; failed commits not cleaned up before retryable updates; meta-service (FDB-like) errors leaving txn state as Fail on the session catalog.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/659cdcaa4a6d89a0. Report an issue: GitHub.

Appendix: source

Thrown at src/query/service/src/catalogs/default/session_catalog.rs:596

            TxnState::AutoCommit => {
                let update_temp_tables = std::mem::take(&mut req.update_temp_tables);
                let reply = if req.is_empty() {
                    Ok(Default::default())
                } else {
                    self.inner
                        .retryable_update_multi_table_meta(tenant, req)
                        .await?
                };
                self.temp_tbl_mgr
                    .lock()
                    .update_multi_table_meta(update_temp_tables);
                Ok(reply)
            }
            TxnState::Active => {
                self.txn_mgr.lock().update_multi_table_meta(tenant, req)?;
                Ok(Ok(Default::default()))
            }
            TxnState::Fail => unreachable!(),
        }
    }

    async fn set_table_row_access_policy(
        &self,
        req: SetTableRowAccessPolicyReq,
    ) -> Result<SetTableRowAccessPolicyReply> {
        if is_temp_table_id(req.table_id) {
            return Err(ErrorCode::StorageUnsupported(format!(
                "SetTableRowAccessPolicy: table id {} is a temporary table id",
                req.table_id
            )));
        }
        self.inner.set_table_row_access_policy(req).await
    }

    async fn set_table_column_mask_policy(
        &self,

View on GitHub (pinned to 288d84d76e)