Nacos Config: parse failures (e.g. duplicate YAML key) are misreported as "config resource does not exist", hiding the real cause

Author: neoLsHCreated Sep 17, 2026Updated Sep 17, 2026

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

  1. On Nacos, create common.yml with the same key written twice:
yaml
single:
  oss:
    path-style-access: true
single:
  oss:
    path-style-access: true
  1. In the app, use spring.config.import: nacos:common.yml (without optional:).
  2. Start the app.
  3. 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] success followed by Error getting properties from nacos carrying a DuplicateKeyException.

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:

java
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:

java
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 / YAMLException

A 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