{"record":{"id":"6155cfbbdb0f4692","repo":"apache/seatunnel","slug":"get-primary-key-failed","errorCode":"GET_PRIMARY_KEY_FAILED","errorMessage":"Cannot get primary key from clickhouse","messagePattern":"Cannot get primary key from clickhouse","errorType":"error_code","errorClass":"ClickhouseConnectorException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/util/ClickhouseProxy.java","lineNumber":407,"sourceCode":"                \"SELECT\\n\"\n                        + \"    name as column_name\\n\"\n                        + \"FROM system.columns\\n\"\n                        + \"WHERE table = '\"\n                        + table\n                        + \"'\\n\"\n                        + \"  AND database = '\"\n                        + schema\n                        + \"'\\n\"\n                        + \"  AND is_in_primary_key = 1\\n\"\n                        + \"ORDER BY position;\";\n        try (ClickHouseResponse response = clickhouseRequest.query(sql).executeAndWait()) {\n            Iterable<ClickHouseRecord> records = response.records();\n            pkFields =\n                    StreamSupport.stream(records.spliterator(), false)\n                            .map(r -> r.getValue(0).asString())\n                            .collect(Collectors.toList());\n        } catch (ClickHouseException e) {\n            throw new ClickhouseConnectorException(\n                    SeaTunnelAPIErrorCode.GET_PRIMARY_KEY_FAILED,\n                    \"Cannot get primary key from clickhouse\",\n                    e);\n        }\n        if (!pkFields.isEmpty()) {\n            // PK_NAME maybe null according to the javadoc, generate a unique name in that case\n            String pkName = \"pk_\" + String.join(\"_\", pkFields);\n            return Optional.of(PrimaryKey.of(pkName, pkFields));\n        }\n        return Optional.empty();\n    }\n\n    public boolean isExistsData(String tableName) throws ExecutionException, InterruptedException {\n        String queryDataSql = \"SELECT count(*) FROM \" + tableName;\n        try (ClickHouseResponse response = clickhouseRequest.query(queryDataSql).executeAndWait()) {\n            return response.firstRecord().getValue(0).asInteger() > 0;\n        } catch (ClickHouseException e) {\n            throw new ClickhouseConnectorException(","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/util/ClickhouseProxy.java#L389-L425","documentation":"ClickhouseProxy.getPrimaryKey queries primary-key metadata (via system tables/JDBC metadata) and wraps ClickHouseException into a ClickhouseConnectorException with GET_PRIMARY_KEY_FAILED. It means the connector could not determine which columns form the primary/replica key, which is required for key-based writes or dedup.","triggerScenarios":"Calling getPrimaryKey when the metadata query throws ClickHouseException (connection/auth/permission failure) or the underlying metadata lookup fails for the target table.","commonSituations":"Table uses an engine without a primary key (e.g. plain Log/StripeLog) and the metadata query errors; user lacks privileges for key metadata lookups; connection dropped during the query.","solutions":["Verify the table engine actually defines a primary key: SHOW CREATE TABLE <table>;","Check the wrapped ClickHouseException cause for auth/connection issues","If the table has no PK, configure the connector's key fields explicitly instead of relying on auto-detection","Grant the user access to the metadata tables used for key lookup"],"exampleFix":"// before\nList<String> pk = proxy.getPrimaryKey(\"default\", \"log_events\"); // Log engine, no PK\n// after\nList<String> pk = proxy.getPrimaryKey(\"default\", \"events\"); -- MergeTree ORDER BY (id, ts)","handlingStrategy":"try-catch","validationCode":"// only auto-detect PK on engines that support keys (MergeTree family)\nClickhouseTable t = proxy.getClickhouseTable(request, database, table);\nboolean supportsPk = t.getEngine().contains(\"MergeTree\");","typeGuard":"boolean engineSupportsPk = engine != null && (engine.startsWith(\"MergeTree\") || engine.startsWith(\"ReplicatedMergeTree\") || engine.startsWith(\"Replacing\"));","tryCatchPattern":"try {\n    List<String> pk = proxy.getPrimaryKey(database, table);\n    if (pk.isEmpty()) { /* configure key fields explicitly */ }\n} catch (ClickhouseConnectorException e) {\n    if (SeaTunnelAPIErrorCode.GET_PRIMARY_KEY_FAILED.equals(e.getSeaTunnelAPIErrorCode())) {\n        LOG.warn(\"PK lookup failed for {}.{}; falling back to configured key fields\", database, table);\n    }\n    throw e;\n}","preventionTips":["Use MergeTree-family engines so a primary key exists","Provide explicit key fields in connector config rather than relying on detection","Grant access to the metadata tables used for key lookup","Inspect the wrapped ClickHouseException for auth/connection root causes"],"tags":["clickhouse","primary-key","metadata"],"backgroundTag":"database-query-failed","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"}