apache/seatunnel · error · OptionValidationException
'schema' must be configured when using a root-level 'query'
Error message
'schema' must be configured when using a root-level 'query'
What it means
Neo4jSourceFactory's root-level query validator requires a 'schema' block whenever a root-level 'query' is used in the Neo4j source config. Without an explicit schema, the connector cannot map the Cypher query result columns to SeaTunnel catalog columns (table name, columns, types). It throws OptionValidationException during option validation, before the job starts.
Solutions
- Add a root-level 'schema' block with table_name, columns (name/type pairs) matching the Cypher result.
- If you don't want a schema, switch to 'tables_configs' with per-entry query + schema instead of a root-level 'query'.
- Ensure the schema block is non-empty (an empty map still triggers the error).
Example fix
// before
source {
Neo4j {
uri = "bolt://localhost:7687"
query = "MATCH (n:Person) RETURN n.name AS name, n.age AS age"
}
}
// after
source {
Neo4j {
uri = "bolt://localhost:7687"
query = "MATCH (n:Person) RETURN n.name AS name, n.age AS age"
schema = {
table = "person"
columns = [
{ name = name, type = string }
{ name = age, type = int }
]
}
}
} Defensive patterns
Strategy: validation
Validate before calling
if (config.hasPath("query") && (!config.hasPath("schema") || config.getConfig("schema").isEmpty())) {
throw new IllegalArgumentException("root-level 'query' requires a non-empty 'schema'");
} Prevention
- Always pair a root-level 'query' with a complete schema (table + columns).
- Use tables_configs mode if you cannot provide a root schema.
- Validate the config locally with a dry-run before submitting the job.
When it happens
Trigger: Configuring a Neo4j source with a root-level 'query' option (Cypher statement) while omitting the root-level 'schema' option, or supplying an empty schema map. evaluate(ReadonlyConfig, String) throws when config.getOptional(ConnectorCommonOptions.SCHEMA) is absent or empty.
Common situations: Users copy a query-based Neo4j source example but delete the schema section; users migrating from table_configs-style configs forget schema is mandatory with root-level query; auto-generated configs omit schema because the connector cannot infer it from Cypher.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- tables_configs[ ]: 'schema' must be configured and non-empty
- root-level 'schema' cannot be used with 'tables_configs'
- tables_configs[ ]: duplicate 'schema.table' value
- tables_configs[ ]: 'query' must be configured and non-blank
- tables_configs[ ]: 'schema.table' must be configured and…
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/3eea933890b42653.
Report an issue: GitHub.
Appendix: source
Thrown at seatunnel-connectors-v2/connector-neo4j/src/main/java/org/apache/seatunnel/connectors/seatunnel/neo4j/source/Neo4jSourceFactory.java:178
private static Neo4jConnectorException configError(String message) {
return new Neo4jConnectorException(SeaTunnelAPIErrorCode.CONFIG_VALIDATION_FAILED, message);
}
static class SingleTableConfigValidator implements ConditionExtension<String> {
@Override
public String description() {
return "'schema' must be configured when using a root-level 'query'";
}
@Override
public boolean evaluate(ReadonlyConfig config, String query)
throws OptionValidationException {
Map<String, Object> schema =
config.getOptional(ConnectorCommonOptions.SCHEMA).orElse(null);
if (schema == null || schema.isEmpty()) {
throw new OptionValidationException(
"'schema' must be configured when using a root-level 'query'");
}
return true;
}
}
static class TableConfigsValidator implements ConditionExtension<List<Map<String, Object>>> {
@Override
public String description() {
return "each 'tables_configs' entry must contain a non-blank 'query' and a schema with a unique 'table'";
}
@Override
public boolean evaluate(ReadonlyConfig config, List<Map<String, Object>> entries)
throws OptionValidationException {
if (config.getOptional(ConnectorCommonOptions.SCHEMA).isPresent()) {
throw new OptionValidationException(View on GitHub (pinned to cf67b549a7)