{"record":{"id":"fb5fef2719a90eaa","repo":"apache/dolphinscheduler","slug":"the-ephemeral-data-can-only-be-updated-by-its-ow","errorCode":null,"errorMessage":"The EPHEMERAL data:  can only be updated by its owner:  but not: ","messagePattern":"The EPHEMERAL data:  can only be updated by its owner:  but not: ","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-registry/dolphinscheduler-registry-plugins/dolphinscheduler-registry-jdbc/src/main/java/org/apache/dolphinscheduler/plugin/registry/jdbc/server/JdbcRegistryDataManager.java","lineNumber":187,"sourceCode":"    @Override\n    public void putJdbcRegistryData(Long clientId, String key, String value, DataType dataType) {\n        checkNotNull(clientId);\n        checkNotNull(key);\n        checkNotNull(dataType);\n\n        final Optional<JdbcRegistryDataDTO> jdbcRegistryDataOptional = jdbcRegistryDataRepository.selectByKey(key);\n\n        jdbcRegistryTransactionTemplate.execute(status -> {\n            if (jdbcRegistryDataOptional.isPresent()) {\n                JdbcRegistryDataDTO jdbcRegistryData = jdbcRegistryDataOptional.get();\n                if (!dataType.name().equals(jdbcRegistryData.getDataType())) {\n                    throw new UnsupportedOperationException(\"The data type: \" + jdbcRegistryData.getDataType()\n                            + \" of the key: \" + key + \" cannot be updated\");\n                }\n\n                if (DataType.EPHEMERAL.name().equals(jdbcRegistryData.getDataType())) {\n                    if (!jdbcRegistryData.getClientId().equals(clientId)) {\n                        throw new UnsupportedOperationException(\n                                \"The EPHEMERAL data: \" + key + \" can only be updated by its owner: \"\n                                        + jdbcRegistryData.getClientId() + \" but not: \" + clientId);\n                    }\n                }\n\n                jdbcRegistryData.setDataValue(value);\n                jdbcRegistryData.setLastUpdateTime(new Date());\n                jdbcRegistryDataRepository.updateById(jdbcRegistryData);\n\n                JdbcRegistryDataChangeEventDTO jdbcRegistryDataChangeEvent = JdbcRegistryDataChangeEventDTO.builder()\n                        .jdbcRegistryData(jdbcRegistryData)\n                        .eventType(JdbcRegistryDataChangeEventDTO.EventType.UPDATE)\n                        .createTime(new Date())\n                        .build();\n                jdbcRegistryDataChangeEventRepository.insert(jdbcRegistryDataChangeEvent);\n            } else {\n                JdbcRegistryDataDTO jdbcRegistryDataDTO = JdbcRegistryDataDTO.builder()\n                        .clientId(clientId)","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-registry/dolphinscheduler-registry-plugins/dolphinscheduler-registry-jdbc/src/main/java/org/apache/dolphinscheduler/plugin/registry/jdbc/server/JdbcRegistryDataManager.java#L169-L205","documentation":"JdbcRegistryDataManager.putJdbcRegistryData enforces that EPHEMERAL data can only be overwritten by the client (clientId) that created it. A put from a different client on a key owned by another live session throws UnsupportedOperationException. This prevents one server instance from hijacking another instance's ephemeral session nodes.","triggerScenarios":"Client A calling put on a key whose jdbcRegistryData.clientId is client B; multiple DolphinScheduler servers writing the same ephemeral key (e.g. a task or master ephemeral path) concurrently; a restarted instance reusing a key path still owned by its dead-but-unexpired previous clientId.","commonSituations":"Key still exists from a crashed instance because its session hasn't timed out, misconfigured identical ephemeral paths across instances, load-distributed writers assuming shared ownership of ephemeral keys.","solutions":["Use unique per-client key paths (include clientId/host) for ephemeral data","Wait for the old owner's session to expire or delete the key with the owner client before rewriting","Use PERSISTENT data instead if multiple clients must write the same key"],"exampleFix":"// before\nregistryClient.put(\"/nodes/master/lock\", value, DataType.EPHEMERAL); // written by all instances\n// after\nString ownedKey = \"/nodes/master/lock/\" + clientId;\nregistryClient.put(ownedKey, value, DataType.EPHEMERAL);","handlingStrategy":"try-catch","validationCode":"JdbcRegistryDataDTO d = repository.selectByKey(key).orElse(null); if (d != null && DataType.EPHEMERAL.name().equals(d.getDataType()) && !d.getClientId().equals(myClientId)) { skipWrite(key); }","typeGuard":null,"tryCatchPattern":"try { manager.putJdbcRegistryData(key, value, DataType.EPHEMERAL, clientId); } catch (UnsupportedOperationException e) { log.error(\"Not owner of ephemeral {}: {}\", key, e.getMessage()); }","preventionTips":["Namespace ephemeral keys with clientId or host","Treat foreign ephemeral keys as read-only","Use persistent data for multi-writer keys"],"tags":["registry","ownership","ephemeral-node"],"backgroundTag":"permission-denied","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}