alibaba/spring-cloud-alibaba · error · NacosRuntimeException
4000
4000
Error message
AbstractConfigChangeListener only support basic java data type for yaml. If you want to listen key changes for custom classes, please use `Listener` to listener whole yaml configuration and parse it by yourself.
What it means
Thrown by ScaYamlConfigChangeParser (a Nacos YAML change parser) when SnakeYAML's SafeConstructor cannot materialize a value during config-change diffing — specifically when the YAMLException message starts with 'could not determine a constructor for the tag' or the exception is a ComposerException. SafeConstructor only accepts plain Java scalars/maps/lists, so custom YAML tags or non-basic types cannot be diffed; the parser raises NacosRuntimeException with code 4000 (NacosException.INVALID_PARAM) guiding the user to listen on the whole config instead. It occurs at config-refresh time when AbstractConfigChangeListener key-level diffing runs.
Source
Thrown at spring-cloud-alibaba-starters/spring-alibaba-nacos-config/src/main/java/com/alibaba/cloud/nacos/annotation/ScaYamlConfigChangeParser.java:68
oldMap = yaml.load(oldContent);
oldMap = getFlattenedMap(oldMap);
}
if (StringUtils.isNotBlank(newContent)) {
newMap = yaml.load(newContent);
newMap = getFlattenedMap(newMap);
}
}
catch (MarkedYAMLException e) {
handleYamlException(e);
}
return filterChangeData(oldMap, newMap);
}
private void handleYamlException(MarkedYAMLException e) {
String message = e.getMessage();
if ((message != null && message.startsWith(INVALID_CONSTRUCTOR_ERROR_INFO)) || e instanceof ComposerException) {
throw new NacosRuntimeException(NacosException.INVALID_PARAM,
"AbstractConfigChangeListener only support basic java data type for yaml. If you want to listen "
+ "key changes for custom classes, please use `Listener` to listener whole yaml configuration and parse it by yourself.",
e);
}
throw e;
}
private Map<String, Object> getFlattenedMap(Map<String, Object> source) {
Map<String, Object> result = new LinkedHashMap<>(128);
buildFlattenedMap(result, source, null);
return result;
}
private void buildFlattenedMap(Map<String, Object> result, Map<String, Object> source, @Nullable String path) {
for (Map.Entry<String, Object> e : source.entrySet()) {
String key = e.getKey();
if (StringUtils.isNotBlank(path)) {View on GitHub (pinned to 115d590110)
Solutions
- Restrict YAML listened via key-level change listeners to basic Java data types (scalars, maps, lists).
- For custom classes, register a whole-config Listener, receive the raw YAML, and parse/diff it yourself (as the message instructs).
- Remove custom `!!tag` constructs from the published YAML or replace them with plain maps.
Example fix
// before: key-level listener on YAML with a custom tag
dataId=app.yml content: service: !!com.example.Endpoint { host: x }
// after: plain basic types, or use a whole-config Listener
service:
host: x
// (and parse/diff custom classes yourself via com.alibaba.nacos.api.config.listener.Listener) Defensive patterns
Strategy: try-catch
Validate before calling
// Before relying on key-level YAML diff, validate the YAML loads under SafeConstructor with no custom tags.
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions()));
try {
yaml.load(publishedYaml);
} catch (MarkedYAMLException e) {
// do not use key-level change listener for this content
} Type guard
static boolean isSafeBasicYaml(String content) {
try {
Object o = new Yaml(new SafeConstructor(new LoaderOptions())).load(content);
return o == null || o instanceof Map;
} catch (RuntimeException e) {
return false;
}
} Try / catch
try {
// key-level change handling
} catch (NacosRuntimeException e) {
if (e.getCode() == NacosException.INVALID_PARAM) {
// fall back to whole-config Listener and parse/diff yourself
}
} Prevention
- Keep key-level-listened YAML to scalars/maps/lists only.
- For custom classes, listen to the whole config and parse it yourself.
- Avoid custom !!tags and unresolvable anchors in published YAML.
When it happens
Trigger: A Nacos YAML config that contains a custom/complex tag (e.g., !!com.example.MyType {...}), an anchor/alias structure SnakeYAML's SafeConstructor rejects, or any non-basic Java type, is changed while a key-level config-change listener (AbstractConfigChangeListener / @NacosConfigKeysChangeListener on yaml) is registered. On the next publish, the diff parser fails.
Common situations: Publishing YAML with custom Java object tags expected to bind to @ConfigurationProperties; using anchors/merge keys that the safe parser can't flatten; binding custom classes from YAML while relying on key-level change notifications.
Related errors
- ConfigService is not initialized
- Invalid date format
- NacosConfigKeysChangeListener must be marked as a single par
- @NacosConfigListener must be over a method with a single p
- ApplicationContext not set
AI-assisted analysis of alibaba/spring-cloud-alibaba@115d590110 (2026-08-14).
Data as JSON: /api/errors/78a191f814532c3d.
Report an issue: GitHub.