t8y2/dbx · error
Delimited stream ended before providing a header
Error message
Delimited stream ended before providing a header
What it means
Raised when a delimited (CSV/TSV) import stream finishes without ever yielding a header row. The producer task ended (closed the channel) without sending columns, so the importer returns the generic fallback message instead of a concrete producer error. This guards the import pipeline from proceeding with zero columns.
Source
Thrown at crates/dbx-core/src/table_import.rs:6073
let _ = producer.await;
return Err(emit_import_error(
&mut progress_callback,
request,
0,
total_rows,
started_at,
"Delimited stream did not provide a header before data rows",
));
}
Some(Err(error)) => {
let _ = producer.await;
return Err(emit_import_error(&mut progress_callback, request, 0, total_rows, started_at, error));
}
None => {
let error = producer
.await
.map_err(|error| error.to_string())?
.err()
.unwrap_or_else(|| "Delimited stream ended before providing a header".to_string());
return Err(emit_import_error(&mut progress_callback, request, 0, total_rows, started_at, error));
}
};
if columns.is_empty() {
drop(receiver);
let _ = producer.await;
return Err(emit_import_error(
&mut progress_callback,
request,
0,
total_rows,
started_at,
"Import file has no columns in the selected row range",
));
}
if let Err(error) = mapping_indexes_for_columns(&columns, &request.mappings) {
drop(receiver);View on GitHub (pinned to c0390bff16)
Solutions
- Check the source file is non-empty and starts with a valid header row delimited by the configured separator
- Verify the import request's file path/handle points to real data, not an empty or truncated file
- Confirm the delimiter and encoding options match the actual file format
- Inspect any error the producer returned before the fallback message (the code surfaces producer.err() if present)
Example fix
// before
import_csv("empty.csv", ',') // stream ends, no header
// after
ensure file starts with: id,name,email\n... before calling the import API Defensive patterns
Strategy: validation
Validate before calling
fn ensure_delimited_has_header(path: &Path, delim: u8) -> Result<(), String> {
let data = std::fs::read(path).map_err(|e| e.to_string())?;
let trimmed: Vec<u8> = data.iter().copied().skip_while(|b| *b == 0xEF).collect(); // skip BOM-ish
if trimmed.iter().all(|b| b.is_ascii_whitespace()) {
return Err("file is empty or whitespace-only".into());
}
if !trimmed.contains(&b'\n') && !trimmed.contains(&delim) {
return Err("no header row detected".into());
}
Ok(())
} Type guard
fn has_header(first_record: Option<Vec<String>>) -> bool {
matches!(first_record, Some(cols) if !cols.is_empty())
} Try / catch
match importer.import_delimited(request) {
Err(msg) if msg.contains("Delimited stream ended before providing a header") => {
eprintln!("Source file has no header/rows: check the file and delimiter");
}
other => other?,
} Prevention
- Check file size > 0 before importing
- Validate the first line contains the expected delimiter and column names
- Verify sheet/file selection and encoding options
- Catch truncated downloads with checksum/size checks
When it happens
Trigger: Importing an empty delimited file; a producer task that returns Ok(None) because the reader hit EOF immediately (e.g. blank or header-less CSV); a parsing backend that silently drops all rows so no header is ever emitted.
Common situations: Uploading a 0-byte CSV; a file containing only BOM or whitespace; an export tool that wrote nothing; wrong delimiter causing the parser to treat the whole file as one empty record; truncated download.
Related errors
- Excel stream ended before providing a header
- runCommand requires a non-empty command document
- Index keys are required
- dropIndexes only accepts non-empty string arrays
- sql is required
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/8f4269fb5d751a52.
Report an issue: GitHub.