{"record":{"id":"4a9a0b8a8ca519fa","repo":"databendlabs/databend","slug":"internal-error-entered-unreachable-code-4a9a0b","errorCode":null,"errorMessage":"internal error: entered unreachable code","messagePattern":"internal error: entered unreachable code","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/query/storages/common/stage/src/read/cast.rs","lineNumber":59,"sourceCode":"///\n/// ## Permitting Casts:\n///\n///  - Specificity: Encourages loading into a more specific type, as it typically requires less storage or provides more information. which is valuable in ETL processes.\n///     -  Often accompanied by safety measures: Requires a specific format, and any mismatch will readily trigger an error, minimizing significant issues in production.\n///  - 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.\n///  - 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.\n///     - but maybe not a big issue, since user can start with infer_schema.\npub fn load_can_auto_cast_to(from_type: &DataType, to_type: &DataType) -> bool {\n    use DataType::*;\n    use NumberDataType::*;\n    // note this does not cover diff Number(_) | Decimal(_)\n    if from_type == to_type {\n        return true;\n    }\n    // we mainly care about which types can/cannot cast to to_type.\n    // the match branches is grouped in a way to make it easier to read this info.\n    match (from_type, to_type) {\n        (_, Null | EmptyArray | EmptyMap | Generic(_) | StageLocation) => unreachable!(),\n\n        // ====  remove null first, all trivial\n        (Null, Nullable(_)) => true,\n        (Nullable(box from_ty), Nullable(box to_ty))\n        | (from_ty, Nullable(box to_ty))\n        | (Nullable(box from_ty), to_ty) => load_can_auto_cast_to(from_ty, to_ty),\n\n        // ==== dive into nested types, must from the same out type, all trivial\n        (Map(box from_ty), Map(box to_ty)) => match (from_ty, to_ty) {\n            (Tuple(_), Tuple(_)) => load_can_auto_cast_to(from_ty, to_ty),\n            (_, _) => unreachable!(),\n        },\n        (EmptyMap, Map(_)) => true,\n        (_, Map(_)) | (Map(_), _) => false,\n\n        (Tuple(from_tys), Tuple(to_tys)) => {\n            from_tys.len() == to_tys.len()\n                && from_tys","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/query/storages/common/stage/src/read/cast.rs#L41-L77","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet target = DataType::Generic(0); // unresolved type in projection\nassert!(load_can_auto_cast_to(&from_ty, &target));\n// after\nlet target = resolve_generic(&target, &schema)?; // resolve to a concrete DataType first\nassert!(load_can_auto_cast_to(&from_ty, &target));","handlingStrategy":"validation","validationCode":"// rust: before invoking stage auto-cast logic\nfn is_valid_target(ty: &DataType) -> bool {\n    !matches!(ty, DataType::Null | DataType::EmptyArray | DataType::EmptyMap\n        | DataType::Generic(_) | DataType::StageLocation)\n}\nassert!(is_valid_target(&target_type), \"target type cannot be auto-cast target\");","typeGuard":"fn is_concrete_type(ty: &DataType) -> bool {\n    !matches!(ty, DataType::Null | DataType::EmptyArray | DataType::EmptyMap\n        | DataType::Generic(_) | DataType::StageLocation)\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["rust","panic","unreachable","stage","type-cast"],"backgroundTag":"internal-invariant-violation","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}