databendlabs/databend · error
table name is provided
Error message
table name is provided
What it means
validate_real_table_alter_access (src/query/service/src/interpreters/access/privilege_access.rs:787) asserts that when validating ALTER access on a table index, the ObjectId resolved from the name is always ObjectId::Table. If it is ObjectId::Database instead, the code panics with unreachable!("table name is provided"). The message is misleading — the panic means a database-level object reached table-level alter validation.
Solutions
- Check the statement's target identifier — ensure it names an existing table, not a database, and correct any typo in the table name
- Fully qualify the table as <catalog>.<database>.<table> to avoid ambiguity in name resolution
- Upgrade to a version where validate_real_table_alter_access returns a PermissionDenied/NotFound error instead of panicking on non-table objects
- As a code fix, replace unreachable! with Err(ErrorCode::PermissionDenied(...)) handling the ObjectId::Database case
Example fix
// before
Ok(ObjectId::Database(_)) => unreachable!("table name is provided"),
// after
Ok(ObjectId::Database(_)) => Err(ErrorCode::PermissionDenied(
"expected a table for table index alter access, got a database".to_string(),
)), Defensive patterns
Strategy: validation
Validate before calling
-- verify the target resolves to a table before ALTER SHOW TABLES LIKE '<name>' IN <database>; -- if empty, the name is a database or typo — do not run ALTER
Type guard
match object_id {
ObjectId::Table(_) => { /* proceed with alter validation */ }
_ => return Err(ErrorCode::PermissionDenied("table index alter requires a table object".into())),
} Try / catch
// fully qualify to remove ambiguity
if !(name.database.is_some() && name.table.is_some()) {
return Err(ErrorCode::BadArguments("ALTER target must be <db>.<table>".into()));
} Prevention
- Always fully qualify ALTER targets as catalog.database.table
- Check for database/table name collisions before naming objects
- Verify the object kind with SHOW TABLES / SHOW DATABASES before ALTER
- Upgrade to builds that return errors instead of panicking on wrong object kinds
When it happens
Trigger: validate_table_index_alter_or_super_access resolves a name to an ObjectId and calls validate_real_table_alter_access; the panic fires when the resolved object is a database rather than a table — e.g. an ALTER statement naming a database (or a name that resolves to a database) is passed through the table-index alter validation path.
Common situations: Running ALTER TABLE ... (index-related alter) where the target name is mistyped or refers to a database; hitting name-resolution ambiguity between a database and table of the same name; upgraded clients issuing ALTER on index objects through changed validation paths.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- logic error: expected CreateTable plan
- internal error: entered unreachable code
- internal error: entered unreachable code
- Input plan must be Query, but it's
- Input plan must be Query, but it's
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/1bbb7941f9bb4884.
Report an issue: GitHub.
Appendix: source
Thrown at src/query/service/src/interpreters/access/privilege_access.rs:787
.await?
.iter()
.map(|r| r.name.clone())
.collect::<Vec<_>>()
.join(",");
Err(ErrorCode::PermissionDenied(format!(
"Permission denied: privilege [{:?}] is required on '{}'.'{}'.'{}' for user {} with roles [{}]",
UserPrivilegeType::Alter,
catalog_name,
db_name,
table_name,
¤t_user.identity().display(),
roles_name,
)))
}
Err(err) => Err(err),
}
}
Ok(ObjectId::Database(_)) => unreachable!("table name is provided"),
Err(err) => Err(err.add_message("error on validating table index access")),
}
}
Err(err) => Err(err),
}
}
async fn validate_warehouse_ownership(
&self,
warehouse: String,
current_user: String,
) -> Option<Result<()>> {
let session = self.ctx.get_current_session();
let warehouse_mgr = GlobalInstance::get::<Arc<dyn ResourcesManagement>>();
// Only check support_forward_warehouse_request privileges
if !warehouse_mgr.support_forward_warehouse_request() {
return Some(Ok(()));View on GitHub (pinned to 288d84d76e)