Nacos Config: parse failures (e.g. duplicate YAML key) are misreported as "config resource does not exist", hiding the real cause
Which Component
Nacos Config (spring-cloud-starter-alibaba-nacos-config)
Describe the bug
When loading config via spring.config.import: nacos:xxx, if the content pulled from the server fails to parse (duplicate YAML key, non-UTF8 encoding, YAML syntax error, ...), NacosConfigDataLoader catches the parse exception and rethrows ConfigDataResourceNotFoundException. Spring Boot then reports:
Config data resource 'NacosConfigDataResource{...}' via location 'nacos:common.yml' does not exist
Action: Check that the value 'nacos:common.yml' ... is correct, or prefix it with 'optional:'This is misleading — the config was fetched successfully; only parsing failed. Users get pushed toward optional: (which would silently skip the config) or hunting for a "missing" config, instead of fixing the real parse error.
Simplest demo
No standalone demo repo needed — the minimal reproduce is just a Nacos config containing a duplicate key + spring.config.import (see To Reproduce below).
To Reproduce
- On Nacos, create
common.ymlwith the same key written twice:
single:
oss:
path-style-access: true
single:
oss:
path-style-access: true- In the app, use
spring.config.import: nacos:common.yml(withoutoptional:). - Start the app.
- Startup fails with "... does not exist / prefix it with 'optional:'", even though the config exists and was fetched. In the logs you'll see
[Nacos Config] Load config[dataId=common.yml] successfollowed byError getting properties from nacoscarrying aDuplicateKeyException.
Expected behavior
Distinguish "cannot fetch" from "fetched but failed to parse". A parse failure should surface the real exception (or a clear "failed to parse config content: ") instead of "resource does not exist". optional: should mean "config not available", not "config present but unparseable" — otherwise optional: silently hides a genuinely broken config.
Screenshots
N/A
Additional context
Root cause in NacosConfigDataLoader (module spring-alibaba-nacos-config, package com.alibaba.cloud.nacos.configdata), observed on branch 2025.1.x:
doLoad() wraps the whole pullConfig() call in one try, and the catch treats fetch-failure and parse-failure identically:
catch (Exception e) { // L105
log.error("Error getting properties from nacos: " + resource, e); // L106 — real cause only lands here
if (!resource.isOptional()) { // L107
throw new ConfigDataResourceNotFoundException(resource, e); // L108 — becomes "does not exist"
}
}But pullConfig() does both the fetch and the parse in one method:
config = configService.getConfig(dataId, group, timeout); // L161 — fetch: succeeds
logLoadInfo(group, dataId, config); // L168 — logs "Load config ... success"
return NacosDataParserHandler.getInstance()
.parseNacosData(configName, config, suffix); // L171 — parse: throws DuplicateKeyException / YAMLExceptionA parse exception from L171 bubbles into the L105 catch and is rethrown as ConfigDataResourceNotFoundException at L108; the real cause survives only in the L106 log and the exception's cause.
This path isn't new: #2745 (a Chinese comment causing MalformedInputException) hit the same "does not exist" report back in the 2021.x era — but that discussion focused on "should Chinese be supported", and the misleading-error root cause was never addressed.
Happy to send a PR if the maintainers agree on the direction.
Source: alibaba/spring-cloud-alibaba