{"record":{"id":"92b276219fd03994","repo":"apache/dolphinscheduler","slug":"the-data-type-of-the-key-cannot-be-updated","errorCode":null,"errorMessage":"The data type:  of the key:  cannot be updated","messagePattern":"The data type:  of the key:  cannot be updated","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":181,"sourceCode":"        return jdbcRegistryDataRepository.selectAll()\n                .stream()\n                .filter(jdbcRegistryDataDTO -> KeyUtils.isParent(key, jdbcRegistryDataDTO.getDataKey()))\n                .collect(Collectors.toList());\n    }\n\n    @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)","sourceCodeStart":163,"sourceCodeEnd":199,"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#L163-L199","documentation":"JdbcRegistryDataManager.putJdbcRegistryData rejects updating an existing key with a different data type (PERSISTENT vs EPHEMERAL). Once a key is created with a type, its type is immutable; writes that would change it throw UnsupportedOperationException. This protects clients that rely on ephemeral semantics (session-bound lifetime) from being silently converted to persistent data.","triggerScenarios":"Calling putData on a key that already exists as EPHEMERAL with DataType.PERSISTENT, or vice versa; re-creating a key after a client restart but passing a different DataType than originally used.","commonSituations":"Changing an ephemeral session node to persistent (or back) during refactoring, two components sharing one registry key but constructing DataType differently, stale local code that assumes the key was deleted.","solutions":["Delete the existing key first, then put it again with the desired DataType","Keep a single shared constant/helper for the DataType of each well-known registry key","Check the existing data type via get/getChildren before writing and only set dataValue"],"exampleFix":"// before\nregistryClient.put(key, value, DataType.PERSISTENT); // key was EPHEMERAL\n// after\nif (registryClient.get(key) != null) {\n    registryClient.remove(key);\n}\nregistryClient.put(key, value, DataType.PERSISTENT);","handlingStrategy":"validation","validationCode":"Optional<JdbcRegistryDataDTO> existing = repository.selectByKey(key); DataType effective = existing.map(d -> DataType.valueOf(d.getDataType())).orElse(desired);","typeGuard":null,"tryCatchPattern":"try { manager.putJdbcRegistryData(key, value, dataType, clientId); } catch (UnsupportedOperationException e) { log.error(\"Type conflict on {}: {}\", key, e.getMessage()); }","preventionTips":["Define DataType per key in one shared constant module","Delete-then-put when a type change is truly needed","Read existing type before writing shared keys"],"tags":["registry","state-conflict","unsupported-operation"],"backgroundTag":"invalid-state-transition","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}