databendlabs/databend · critical

internal error: entered unreachable code

Error message

internal error: entered unreachable code

What it means

In resolve_map_access_from_scalar, when accessing a tuple field by name or index on a scalar value, the code matches on the resolved TableDataType and panics with `unreachable!()` for any type that is not a tuple-like structure. It assumes map/tuple access is only routed here for struct (tuple) types; any other type reaching this arm is a type-checking gap.

Solutions

  1. Check the column's declared type with SELECT typeof(col); use the access syntax that matches it (col['k'] for maps, col:k or col['name'] for objects/tuples)
  2. Cast explicitly to the expected type before access: CAST(col AS OBJECT('a' INT)) or CAST(col AS MAP(VARCHAR, VARIANT))
  3. If the column type metadata is wrong, correct the table schema or re-ingest with the proper type
  4. If a genuine Tuple triggers the panic, report a planner bug with the schema and query

Example fix

// before: name access on a Map-typed column
SELECT obj['name'] FROM t; -- obj is MAP(VARCHAR, VARIANT)
// after: cast or use map-appropriate access
SELECT obj['name']::VARIANT FROM t; -- works for Map; or CAST to OBJECT first
Defensive patterns

Strategy: type-guard

Validate before calling

SELECT typeof(col) FROM t LIMIT 1; -- confirm OBJECT/TUPLE before name-based access

Type guard

fn supports_named_field_access(ty: &str) -> bool {
    ty.starts_with("TUPLE(") || ty.starts_with("OBJECT(")
}

Prevention

When it happens

Trigger: Bracket access like expr['field'] or expr[0] on a Variant/Object value whose inferred table data type is neither Tuple nor a struct-backed type — e.g. accessing named fields on a Map or Array-typed scalar, or on an object key when the column's schema type drifted from the actual JSON shape.

Common situations: Semi-structured (JSON/VARIANT) columns where the inferred object/tuple metadata is stale or wrong after schema inference; queries like col['key'] on columns typed as MAP rather than OBJECT; accessing tuple fields by name on values inferred as arrays.

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


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

Appendix: source

Thrown at src/query/sql/src/planner/semantic/type_check/variant.rs:519

                        if idx as usize > fields_type.len() {
                            return Err(ErrorCode::SemanticError(format!(
                                "tuple index {} is out of bounds for length {}",
                                idx,
                                fields_type.len()
                            )));
                        }
                        (idx - 1) as usize
                    }
                    Literal::String(name) => match fields_name.iter().position(|k| k == &name) {
                        Some(idx) => idx,
                        None => {
                            return Err(ErrorCode::SemanticError(format!(
                                "tuple name `{}` does not exist, available names are: {:?}",
                                name, &fields_name
                            )));
                        }
                    },
                    _ => unreachable!(),
                };
                table_data_type = fields_type.get(idx).unwrap().clone();
                let return_type =
                    ScalarExpr::passthrough_nullable_type(DataType::from(&table_data_type), [
                        &scalar,
                    ]);
                scalar = FunctionCall {
                    span: expr_span,
                    func_name: "get".to_string(),
                    params: vec![Scalar::Number(NumberScalar::Int64((idx + 1) as i64))],
                    arguments: vec![scalar.clone()],
                    return_type: Box::new(return_type),
                }
                .into();
                continue;
            }
            let box (path_scalar, _) = self.resolve_literal(span, &path_lit)?;
            table_data_type = match table_data_type {

View on GitHub (pinned to 288d84d76e)