databendlabs/databend · error
internal error: entered unreachable code
Error message
internal error: entered unreachable code
What it means
load_can_auto_cast_to decides whether a stage (external-location) file column type can auto-cast to a target type during COPY/inferring. It panics with unreachable! when the target (to_type) is one of Null, EmptyArray, EmptyMap, Generic(_), or StageLocation, since no real table column should have those types. This is an internal invariant guard: some caller passed a type that should have been rejected earlier in planning.
Solutions
- Inspect the target schema/column types passed to the stage reader and ensure they are concrete, non-generic types
- Check where project_columnar builds its projection types; fix upstream type resolution so Null/EmptyArray/EmptyMap/Generic/StageLocation never become to_type
- If a legitimate new case exists, add a match branch instead of relying on unreachable
- Report the panic with the query and schema to Databend maintainers as a bug
Example fix
// before let target = DataType::Generic(0); // unresolved type in projection assert!(load_can_auto_cast_to(&from_ty, &target)); // after let target = resolve_generic(&target, &schema)?; // resolve to a concrete DataType first assert!(load_can_auto_cast_to(&from_ty, &target));
Defensive patterns
Strategy: validation
Validate before calling
// rust: before invoking stage auto-cast logic
fn is_valid_target(ty: &DataType) -> bool {
!matches!(ty, DataType::Null | DataType::EmptyArray | DataType::EmptyMap
| DataType::Generic(_) | DataType::StageLocation)
}
assert!(is_valid_target(&target_type), "target type cannot be auto-cast target"); Type guard
fn is_concrete_type(ty: &DataType) -> bool {
!matches!(ty, DataType::Null | DataType::EmptyArray | DataType::EmptyMap
| DataType::Generic(_) | DataType::StageLocation)
} Prevention
- Always resolve generic/placeholder types during planning before stage reads
- Add unit tests asserting target schemas of stage queries contain only concrete types
- Validate table schemas after schema inference before building projections
When it happens
Trigger: Calling load_can_auto_cast_to (directly or via project_columnar) with a to_type of DataType::Null, EmptyArray, EmptyMap, Generic(n), or StageLocation while reading a stage file.
Common situations: Table schemas or planned projections containing unresolved/generic or empty-collection types reaching stage read; bugs in schema inference for stage files; hand-built queries targeting synthetic types.
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
- unexpected InternalColumnType in stage file reader
- stage_prefix should never be called on external stage, must…
- plan in InsertInputSource::Stag must be CopyIntoTable
- internal error: entered unreachable code
- internal error: entered unreachable code
AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11).
Data as JSON: /api/errors/4a9a0b8a8ca519fa.
Report an issue: GitHub.
Appendix: source
Thrown at src/query/storages/common/stage/src/read/cast.rs:59
///
/// ## Permitting Casts:
///
/// - Specificity: Encourages loading into a more specific type, as it typically requires less storage or provides more information. which is valuable in ETL processes.
/// - Often accompanied by safety measures: Requires a specific format, and any mismatch will readily trigger an error, minimizing significant issues in production.
/// - Convenience: For instance, Python users might use the Python int type for convenience, which corresponds to int64 in Parquet. Thus, casting from int64 to smaller integers is allowed.
/// - Compatibility: Initially, the rules are based on the intersection of arrow_cast::can_cast_to() and all pairs that are operational from running run_cast, both of which are quite permissive.
/// - but maybe not a big issue, since user can start with infer_schema.
pub fn load_can_auto_cast_to(from_type: &DataType, to_type: &DataType) -> bool {
use DataType::*;
use NumberDataType::*;
// note this does not cover diff Number(_) | Decimal(_)
if from_type == to_type {
return true;
}
// we mainly care about which types can/cannot cast to to_type.
// the match branches is grouped in a way to make it easier to read this info.
match (from_type, to_type) {
(_, Null | EmptyArray | EmptyMap | Generic(_) | StageLocation) => unreachable!(),
// ==== remove null first, all trivial
(Null, Nullable(_)) => true,
(Nullable(box from_ty), Nullable(box to_ty))
| (from_ty, Nullable(box to_ty))
| (Nullable(box from_ty), to_ty) => load_can_auto_cast_to(from_ty, to_ty),
// ==== dive into nested types, must from the same out type, all trivial
(Map(box from_ty), Map(box to_ty)) => match (from_ty, to_ty) {
(Tuple(_), Tuple(_)) => load_can_auto_cast_to(from_ty, to_ty),
(_, _) => unreachable!(),
},
(EmptyMap, Map(_)) => true,
(_, Map(_)) | (Map(_), _) => false,
(Tuple(from_tys), Tuple(to_tys)) => {
from_tys.len() == to_tys.len()
&& from_tysView on GitHub (pinned to 288d84d76e)