{"record":{"id":"c42f219a9edc9f23","repo":"prestodb/presto","slug":"catalog-must-be-present-if-schema-is-present","errorCode":null,"errorMessage":"catalog must be present if schema is present","messagePattern":"catalog must be present if schema is present","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"presto-spi/src/main/java/com/facebook/presto/spi/security/ViewExpression.java","lineNumber":35,"sourceCode":"\nimport static java.util.Objects.requireNonNull;\n\npublic class ViewExpression\n{\n    private final String identity;\n    private final Optional<String> catalog;\n    private final Optional<String> schema;\n    private final String expression;\n\n    public ViewExpression(String identity, Optional<String> catalog, Optional<String> schema, String expression)\n    {\n        this.identity = requireNonNull(identity, \"identity is null\");\n        this.catalog = requireNonNull(catalog, \"catalog is null\");\n        this.schema = requireNonNull(schema, \"schema is null\");\n        this.expression = requireNonNull(expression, \"expression is null\");\n\n        if (!catalog.isPresent() && schema.isPresent()) {\n            throw new IllegalArgumentException(\"catalog must be present if schema is present\");\n        }\n    }\n\n    public String getIdentity()\n    {\n        return identity;\n    }\n\n    public Optional<String> getCatalog()\n    {\n        return catalog;\n    }\n\n    public Optional<String> getSchema()\n    {\n        return schema;\n    }\n","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-spi/src/main/java/com/facebook/presto/spi/security/ViewExpression.java#L17-L53","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nnew ViewExpression(user, Optional.empty(), Optional.of(\"sales\"), expr); // throws\n// after\nnew ViewExpression(user, Optional.of(\"hive\"), Optional.of(\"sales\"), expr);\n// or unqualified:\nnew ViewExpression(user, Optional.empty(), Optional.empty(), expr);","handlingStrategy":"validation","validationCode":"// validate before constructing ViewExpression\nif (catalog == null && schema != null) {\n    throw new IllegalArgumentException(\"catalog must be present if schema is present\");\n}\nViewExpression v = new ViewExpression(identity, catalog, schema, expression);","typeGuard":"boolean isValidViewExpressionScope(Optional<String> catalog, Optional<String> schema) {\n    return schema == null || !schema.isPresent() || (catalog != null && catalog.isPresent());\n}","tryCatchPattern":"try {\n    return new ViewExpression(identity, catalog, schema, expression);\n} catch (IllegalArgumentException e) {\n    LOG.warn(\"Invalid view expression scope: %s\", e.getMessage());\n    // fall back to a fully qualified or fully unqualified expression\n    return new ViewExpression(identity, catalog, Optional.empty(), expression);\n}","preventionTips":["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"],"tags":["presto","validation","illegal-argument","security"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}