influxdata/influxdb · error · QueryExecutorError
unable to compose record batches from databases
Error message
unable to compose record batches from databases: {0} What it means
This QueryExecutorError::DatabasesToRecordBatch variant wraps an ArrowError raised while converting queried database data into Arrow RecordBatches. The executor built result batches across databases and Arrow rejected the operation (schema merge, construction, or concat failure).
Solutions
- Check that queried databases have compatible table schemas (same column names and Arrow types)
- Run queries against a single database to identify which one's schema breaks composition
- Fix schema drift by migrating the offending table's column types
- Log the wrapped ArrowError to identify the exact field/type conflict
Example fix
// before // SELECT * FROM db1.meas, db2.meas — type mismatch on 'value' // after // align schemas first: // ALTER TABLE db2.meas ALTER COLUMN value SET DATA TYPE FLOAT64;
Defensive patterns
Strategy: try-catch
Validate before calling
// verify schema compatibility before cross-database composition
let schemas = dbs.iter().map(|db| get_table_schema(db, table)).collect::<Result<Vec<_>,_>>()?;
let first = &schemas[0];
for s in &schemas[1..] {
assert_eq!(s.fields(), first.fields(), "schema drift across databases");
} Type guard
fn is_batch_compose_err(e: &QueryExecutorError) -> Option<&ArrowError> {
if let QueryExecutorError::DatabasesToRecordBatch(ae) = e { Some(ae) } else { None }
} Try / catch
match executor.databases_to_record_batch(&dbs) {
Ok(batches) => batches,
Err(QueryExecutorError::DatabasesToRecordBatch(ae)) => {
log::error!("arrow batch composition failed: {ae}");
Err(QueryExecutorError::DatabasesToRecordBatch(ae))
}
Err(e) => Err(e),
} Prevention
- Keep table schemas identical across databases that are queried together
- Run schema-drift checks after migrations
- Compose single-database results when schemas may differ
- Surface ArrowError details in logs
When it happens
Trigger: Executing a query spanning multiple databases whose resulting schemas cannot be unified into record batches; mismatched column types or field nullability when composing batches.
Common situations: Databases with drifted schemas for the same table name (a column changed type between databases); querying across databases after a migration changed field types; empty vs non-empty batch schema conflicts.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- Error creating record batch
- Field not found in table buffer
- unable to compose record batches from retention policies
- unexpected batch schema mismatch: expected
- column id in series key should be valid
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/0f4fcfe022755f0d.
Report an issue: GitHub.
Appendix: source
Thrown at influxdb3_internal_api/src/query_executor.rs:31
use iox_query_influxql::show_retention_policies::InfluxQlShowRetentionPolicies;
use iox_query_params::StatementParams;
use schema::INFLUXQL_MEASUREMENT_COLUMN_NAME;
use std::fmt::Debug;
use std::sync::Arc;
use trace::ctx::SpanContext;
use trace::span::{Span, SpanExt};
use trace_http::ctx::RequestLogContext;
use tracker::InstrumentedAsyncOwnedSemaphorePermit;
#[derive(Debug, thiserror::Error)]
pub enum QueryExecutorError {
#[error("database not found: {db_name}")]
DatabaseNotFound { db_name: String },
#[error("error while planning query: {0}")]
QueryPlanning(#[source] DataFusionError),
#[error("error while executing plan: {0}")]
ExecuteStream(#[source] DataFusionError),
#[error("unable to compose record batches from databases: {0}")]
DatabasesToRecordBatch(#[source] ArrowError),
#[error("unable to compose record batches from retention policies: {0}")]
RetentionPoliciesToRecordBatch(#[source] ArrowError),
#[error("invokded a method that is not implemented: {0}")]
MethodNotImplemented(&'static str),
#[error(transparent)]
Anyhow(#[from] anyhow::Error),
}
#[async_trait]
pub trait QueryExecutor: QueryDatabase + Debug + Send + Sync + 'static {
async fn get_db_namespace(
&self,
database_name: &str,
span_ctx: &Option<SpanContext>,
) -> Result<Arc<dyn QueryNamespace>, QueryExecutorError> {
self.namespace(
database_name,View on GitHub (pinned to 06200ef96b)