apache/seatunnel · error · CouchbaseConnectorException
WRITE_RECORDS_FAILED
WRITE_RECORDS_FAILED
Error message
'upsert-enable' is true but 'primary-key' is not configured. Upsert requires a primary key to build a stable document key.
What it means
The Couchbase sink validates at createSink time that upsert mode has a primary key, because upserts require a deterministic document key. If 'upsert-enable' is true and 'primary-key' is absent or empty, configuration is invalid and job startup fails with WRITE_RECORDS_FAILED.
Source
Thrown at seatunnel-connectors-v2/connector-couchbase/src/main/java/org/apache/seatunnel/connectors/seatunnel/couchbase/sink/CouchbaseSinkFactory.java:79
CouchbaseSinkOptions.UPSERT_ENABLE,
CouchbaseSinkOptions.PRIMARY_KEY)
.build();
}
@Override
public TableSink createSink(TableSinkFactoryContext context) {
ReadonlyConfig config = context.getOptions();
// Issue 2 guard: upsert without a primary key produces random-UUID document keys,
// which breaks upsert semantics. Fail fast here rather than silently degrading.
boolean upsertEnabled =
config.getOptional(CouchbaseSinkOptions.UPSERT_ENABLE).orElse(false);
boolean hasPrimaryKey =
config.getOptional(CouchbaseSinkOptions.PRIMARY_KEY)
.map(keys -> !keys.isEmpty())
.orElse(false);
if (upsertEnabled && !hasPrimaryKey) {
throw new CouchbaseConnectorException(
CouchbaseConnectorErrorCode.WRITE_RECORDS_FAILED,
"'upsert-enable' is true but 'primary-key' is not configured. "
+ "Upsert requires a primary key to build a stable document key.");
}
CouchbaseWriterOptions.Builder builder =
CouchbaseWriterOptions.builder()
.withConnectionString(config.get(CouchbaseSinkOptions.CONNECTION_STRING))
.withUsername(config.get(CouchbaseSinkOptions.USERNAME))
.withPassword(config.get(CouchbaseSinkOptions.PASSWORD))
.withBucket(config.get(CouchbaseSinkOptions.BUCKET))
.withScope(config.get(CouchbaseSinkOptions.SCOPE))
.withCollection(config.get(CouchbaseSinkOptions.COLLECTION));
config.getOptional(CouchbaseSinkOptions.BUFFER_FLUSH_MAX_ROWS)
.ifPresent(builder::withFlushSize);
config.getOptional(CouchbaseSinkOptions.RETRY_MAX).ifPresent(builder::withRetryMax);
config.getOptional(CouchbaseSinkOptions.RETRY_INTERVAL)View on GitHub (pinned to cf67b549a7)
Solutions
- Add primary-key = ["field"] to the sink config
- Set upsert-enable = false if append semantics are intended
- Ensure the configured primary key fields exist in the source schema
Example fix
// before
sink {
Couchbase {
upsert-enable = true
}
}
// after
sink {
Couchbase {
upsert-enable = true
primary-key = ["user_id"]
}
} Defensive patterns
Strategy: validation
Validate before calling
java
boolean upsert = config.getOptional(UPSERT_ENABLE).orElse(false);
boolean hasPk = config.getOptional(PRIMARY_KEY).map(k -> !k.isEmpty()).orElse(false);
if (upsert && !hasPk) throw new IllegalArgumentException("upsert-enable=true requires primary-key"); Try / catch
java
try {
sink = factory.createSink(context);
} catch (CouchbaseConnectorException e) {
// check upsert-enable / primary-key config before resubmitting
} Prevention
- Always pair upsert-enable=true with a primary-key list
- Validate sink configs in CI with a config linter
When it happens
Trigger: Sink config with upsert-enable = true but no primary-key list; primary-key configured as an empty array; programmatic sink creation via CouchbaseSinkFactory.createSink with such options.
Common situations: Copying an upsert example but omitting primary-key; switching a plain append sink config to upsert-enable without adding a key.
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
- Please configure `record_key_fields` of ${tableName}, it is
- Schema config can not be empty
- Can not find catalog table with factoryId [%s]
- Schema config need option [schema], please correct your conf
- Schema config can't contains both [fields] and [columns], pl
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/30823817e1417292.
Report an issue: GitHub.