prestodb/presto · error · IllegalArgumentException
catalog must be present if schema is present
Error message
catalog must be present if schema is present
What it means
ViewExpression's constructor validates that a catalog is present whenever a schema is present, throwing IllegalArgumentException 'catalog must be present if schema is present'. A view/row-filter expression is always anchored to a catalog; a schema without a catalog is an inconsistent, unqualified definition, so the SPI rejects it eagerly.
Source
Thrown at presto-spi/src/main/java/com/facebook/presto/spi/security/ViewExpression.java:35
import static java.util.Objects.requireNonNull;
public class ViewExpression
{
private final String identity;
private final Optional<String> catalog;
private final Optional<String> schema;
private final String expression;
public ViewExpression(String identity, Optional<String> catalog, Optional<String> schema, String expression)
{
this.identity = requireNonNull(identity, "identity is null");
this.catalog = requireNonNull(catalog, "catalog is null");
this.schema = requireNonNull(schema, "schema is null");
this.expression = requireNonNull(expression, "expression is null");
if (!catalog.isPresent() && schema.isPresent()) {
throw new IllegalArgumentException("catalog must be present if schema is present");
}
}
public String getIdentity()
{
return identity;
}
public Optional<String> getCatalog()
{
return catalog;
}
public Optional<String> getSchema()
{
return schema;
}
View on GitHub (pinned to 55bb57d202)
Solutions
- Always supply the catalog: new ViewExpression(identity, Optional.of("catalog"), Optional.of("schema"), expression)
- If the expression is truly unqualified, pass Optional.empty() for BOTH catalog and schema
- Fix the JSON/config producer to emit the catalog property alongside schema
- Add client-side validation that (catalog == null) implies (schema == null) before calling the API
Example fix
// before
new ViewExpression(user, Optional.empty(), Optional.of("sales"), expr); // throws
// after
new ViewExpression(user, Optional.of("hive"), Optional.of("sales"), expr);
// or unqualified:
new ViewExpression(user, Optional.empty(), Optional.empty(), expr); Defensive patterns
Strategy: validation
Validate before calling
// validate before constructing ViewExpression
if (catalog == null && schema != null) {
throw new IllegalArgumentException("catalog must be present if schema is present");
}
ViewExpression v = new ViewExpression(identity, catalog, schema, expression); Type guard
boolean isValidViewExpressionScope(Optional<String> catalog, Optional<String> schema) {
return schema == null || !schema.isPresent() || (catalog != null && catalog.isPresent());
} Try / catch
try {
return new ViewExpression(identity, catalog, schema, expression);
} catch (IllegalArgumentException e) {
LOG.warn("Invalid view expression scope: %s", e.getMessage());
// fall back to a fully qualified or fully unqualified expression
return new ViewExpression(identity, catalog, Optional.empty(), expression);
} Prevention
- Always qualify view expressions with catalog AND schema, or neither
- Validate access-control JSON configs at load time with a schema
- Add unit tests covering the catalog/schema pairing invariant
- Migrate config producers to emit the catalog field explicitly
When it happens
Trigger: Constructing new ViewExpression(identity, Optional.empty() /*catalog*/, Optional.of("schema") /*schema*/, expression), or deserializing JSON where catalog is null/absent but schema is set — e.g. column masks/row filters defined for access control.
Common situations: Hand-written JSON for view expressions in system access control configs omitting catalog; internal tooling building ViewExpression programmatically and passing empty Optional for catalog; migration scripts that drop the catalog field.
Related errors
- id is empty
- Role must be present for the selected role type:
- dictionarySourceIds must be the same
- blocks is empty
- Column does not have same position count (%s) as page (%s)
AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04).
Data as JSON: /api/errors/c42f219a9edc9f23.
Report an issue: GitHub.