{"record":{"id":"30823817e1417292","repo":"apache/seatunnel","slug":"write-records-failed","errorCode":"WRITE_RECORDS_FAILED","errorMessage":"'upsert-enable' is true but 'primary-key' is not configured. Upsert requires a primary key to build a stable document key.","messagePattern":"'upsert-enable' is true but 'primary-key' is not configured\\. Upsert requires a primary key to build a stable document key\\.","errorType":"error_code","errorClass":"CouchbaseConnectorException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-couchbase/src/main/java/org/apache/seatunnel/connectors/seatunnel/couchbase/sink/CouchbaseSinkFactory.java","lineNumber":79,"sourceCode":"                        CouchbaseSinkOptions.UPSERT_ENABLE,\n                        CouchbaseSinkOptions.PRIMARY_KEY)\n                .build();\n    }\n\n    @Override\n    public TableSink createSink(TableSinkFactoryContext context) {\n        ReadonlyConfig config = context.getOptions();\n\n        // Issue 2 guard: upsert without a primary key produces random-UUID document keys,\n        // which breaks upsert semantics. Fail fast here rather than silently degrading.\n        boolean upsertEnabled =\n                config.getOptional(CouchbaseSinkOptions.UPSERT_ENABLE).orElse(false);\n        boolean hasPrimaryKey =\n                config.getOptional(CouchbaseSinkOptions.PRIMARY_KEY)\n                        .map(keys -> !keys.isEmpty())\n                        .orElse(false);\n        if (upsertEnabled && !hasPrimaryKey) {\n            throw new CouchbaseConnectorException(\n                    CouchbaseConnectorErrorCode.WRITE_RECORDS_FAILED,\n                    \"'upsert-enable' is true but 'primary-key' is not configured. \"\n                            + \"Upsert requires a primary key to build a stable document key.\");\n        }\n\n        CouchbaseWriterOptions.Builder builder =\n                CouchbaseWriterOptions.builder()\n                        .withConnectionString(config.get(CouchbaseSinkOptions.CONNECTION_STRING))\n                        .withUsername(config.get(CouchbaseSinkOptions.USERNAME))\n                        .withPassword(config.get(CouchbaseSinkOptions.PASSWORD))\n                        .withBucket(config.get(CouchbaseSinkOptions.BUCKET))\n                        .withScope(config.get(CouchbaseSinkOptions.SCOPE))\n                        .withCollection(config.get(CouchbaseSinkOptions.COLLECTION));\n\n        config.getOptional(CouchbaseSinkOptions.BUFFER_FLUSH_MAX_ROWS)\n                .ifPresent(builder::withFlushSize);\n        config.getOptional(CouchbaseSinkOptions.RETRY_MAX).ifPresent(builder::withRetryMax);\n        config.getOptional(CouchbaseSinkOptions.RETRY_INTERVAL)","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-couchbase/src/main/java/org/apache/seatunnel/connectors/seatunnel/couchbase/sink/CouchbaseSinkFactory.java#L61-L97","documentation":"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.","triggerScenarios":"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.","commonSituations":"Copying an upsert example but omitting primary-key; switching a plain append sink config to upsert-enable without adding a key.","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"],"exampleFix":"// before\nsink {\n  Couchbase {\n    upsert-enable = true\n  }\n}\n// after\nsink {\n  Couchbase {\n    upsert-enable = true\n    primary-key = [\"user_id\"]\n  }\n}","handlingStrategy":"validation","validationCode":"java\nboolean upsert = config.getOptional(UPSERT_ENABLE).orElse(false);\nboolean hasPk = config.getOptional(PRIMARY_KEY).map(k -> !k.isEmpty()).orElse(false);\nif (upsert && !hasPk) throw new IllegalArgumentException(\"upsert-enable=true requires primary-key\");","typeGuard":null,"tryCatchPattern":"java\ntry {\n    sink = factory.createSink(context);\n} catch (CouchbaseConnectorException e) {\n    // check upsert-enable / primary-key config before resubmitting\n}","preventionTips":["Always pair upsert-enable=true with a primary-key list","Validate sink configs in CI with a config linter"],"tags":["config","upsert","couchbase"],"backgroundTag":"missing-required-config-field","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}