prestodb/presto · error · SemanticException
MISSING_TABLE
MISSING_TABLE
Error message
Table name is empty
What it means
MetadataExtractor.populateMetadataHandle collects every table/view name referenced by the analyzed statement and validates them before fetching view definitions. If a collected QualifiedObjectName has an empty object (table) name part, it throws MISSING_TABLE, because metadata cannot be resolved for a nameless table reference.
Source
Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/MetadataExtractor.java:81
this.warningCollector = requireNonNull(warningCollector, "warningCollector is null");
}
public void populateMetadataHandle(Session session, Statement statement, MetadataHandle metadataHandle)
{
if (executor.isPresent() && isPreProcessMetadataCalls(session)) {
metadataHandle.setPreProcessMetadataCalls(true);
populateMetadataHandle(session, statement, metadataHandle, new MetadataExtractorContext());
}
}
private void populateMetadataHandle(Session session, Statement statement, MetadataHandle metadataHandle, MetadataExtractorContext metadataExtractorContext)
{
Visitor visitor = new Visitor(session);
visitor.process(statement, metadataExtractorContext);
metadataExtractorContext.getTableNames().forEach(tableName -> {
if (tableName.getObjectName().isEmpty()) {
throw new SemanticException(MISSING_TABLE, "Table name is empty");
}
if (tableName.getSchemaName().isEmpty()) {
throw new SemanticException(MISSING_SCHEMA, "Schema name is empty");
}
metadataHandle.addViewDefinition(tableName, executor.get().submit(() -> {
Optional<ViewDefinition> optionalView = session.getRuntimeStats().recordWallTime(
GET_VIEW_TIME_NANOS,
() -> metadataResolver.getView(tableName));
if (optionalView.isPresent()) {
ViewDefinition view = optionalView.get();
Statement viewStatement = sqlParser.createStatement(view.getOriginalSql(), createParsingOptions(session, warningCollector));
Session.SessionBuilder viewSessionBuilder = Session.builder(metadata.getSessionPropertyManager())
.setQueryId(session.getQueryId())
.setRuntimeStats(session.getRuntimeStats())
.setTransactionId(session.getTransactionId().orElse(null))
.setIdentity(session.getIdentity())
.setSource(session.getSource().orElse(null))View on GitHub (pinned to 55bb57d202)
Solutions
- Check the submitted SQL for an empty or missing table identifier and fix the statement text.
- If the statement is generated, log/inspect the rendered SQL before execution and guard against empty table-name variables.
- Ensure table names are fully qualified with a non-empty catalog, schema, and object name.
Example fix
// before (generated SQL with empty variable)
String sql = "SELECT * FROM " + schema + "." + table; // table == ""
// after
if (table == null || table.isEmpty()) { throw new IllegalArgumentException("table name required"); }
String sql = "SELECT * FROM \"" + schema + "\".\"" + table + "\""; Defensive patterns
Strategy: validation
Validate before calling
// validate identifiers before submitting statements
function assertValidTableName(name) {
if (!name || name.split(".").filter(Boolean).length === 0) throw new Error("Table name is empty");
} Prevention
- Interpolate table identifiers only after null/empty checks.
- Always use fully-qualified catalog.schema.table names in generated SQL.
- Log the final rendered SQL in staging to catch empty substitutions.
When it happens
Trigger: Statement analysis collects a QualifiedObjectName whose objectName is empty — typically from a malformed or partially parsed table identifier supplied to the metadata extraction path (e.g. empty target of an INSERT or reference built with only catalog/schema).
Common situations: Programmatic statement construction with an empty table identifier; SQL whose table name was lost by an upstream templating/interpolation step (e.g. `SELECT * FROM .schema.` style artifacts).
Related errors
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/1851bd7402db9640.
Report an issue: GitHub.