alibaba/nacos · error · NacosRuntimeException

400

400

Error message

could not determine a constructor for the tag {}{}

What it means

Thrown by YamlParserUtil.ConstructYamlConfigMetadata.construct as a NacosRuntimeException with code NacosException.INVALID_PARAM (400) when a YAML node's tag does not equal the expected CONFIG_METADATA_TAG (the tag bound to com.alibaba.nacos.config.server.model.ConfigMetadata). The parser only knows how to construct nodes tagged as ConfigMetadata; any other root tag is rejected. The message appends the actual tag and its start mark for locating the offending YAML position.

Solutions

  1. Regenerate the metadata YAML via YamlParserUtil.dumpObject(new ConfigMetadata()) so it carries the correct tag, instead of hand-editing it.
  2. If editing is unavoidable, ensure the root node carries the ConfigMetadata tag expected by the running Nacos version.
  3. Validate that the file is a Nacos config-metadata export for this server version before importing.

Example fix

// before (hand-written / generic yaml loaded as ConfigMetadata)
ConfigMetadata md = YamlParserUtil.loadObject(rawYaml, ConfigMetadata.class); // tag mismatch

// after (round-trip through the serializer to guarantee the tag)
String safe = YamlParserUtil.dumpObject(originalMetadata);
ConfigMetadata md = YamlParserUtil.loadObject(safe, ConfigMetadata.class);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the YAML carries the ConfigMetadata tag before parsing.
// Prefer round-tripping through the serializer rather than hand-editing:
String safe = YamlParserUtil.dumpObject(new ConfigMetadata());
String expectedTag = "!<" + ConfigMetadata.class.getName() + ">"; // tag scheme for this version
boolean looksValid = rawYaml != null && rawYaml.contains(ConfigMetadata.class.getName());

Try / catch

try {
    ConfigMetadata md = YamlParserUtil.loadObject(content, ConfigMetadata.class);
} catch (NacosRuntimeException e) {
    if (e.getCode() == NacosException.INVALID_PARAM) {
        // metadata YAML tag mismatch - regenerate from a known-good export
        throw new IllegalArgumentException("Invalid config metadata YAML: " + e.getMessage());
    } else throw e;
}

Prevention

When it happens

Trigger: Calling YamlParserUtil.loadObject(content, ConfigMetadata.class) on a YAML document whose root tag is not the ConfigMetadata tag - e.g. a hand-edited metadata YAML missing the custom tag, a generic YAML map, or a metadata file produced by a different/older Nacos version with a different tag scheme. Also reachable via config export/import metadata parsing.

Common situations: Re-importing a config-metadata YAML that was edited externally (tag stripped/renamed), loading a plain YAML as ConfigMetadata, version mismatch between the exporter and importer, or a truncated/corrupted metadata file.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/7a5be0428405a5ca. Report an issue: GitHub.

Appendix: source

Thrown at config/src/main/java/com/alibaba/nacos/config/server/utils/YamlParserUtil.java:107

        protected NodeTuple representJavaBeanProperty(Object javaBean, Property property,
            Object propertyValue,
            Tag customTag) {
            if (propertyValue == null) {
                return null;
            } else {
                return super.representJavaBeanProperty(javaBean, property, propertyValue,
                    customTag);
            }
        }
    }
    
    public static class ConstructYamlConfigMetadata extends AbstractConstruct {
        
        @Override
        public Object construct(Node node) {
            if (!YamlParserConstructor.CONFIG_METADATA_TAG.getValue()
                .equals(node.getTag().getValue())) {
                throw new NacosRuntimeException(NacosException.INVALID_PARAM,
                    "could not determine a constructor for the tag " + node.getTag()
                        + node.getStartMark());
            }
            
            MappingNode mNode = (MappingNode) node;
            List<NodeTuple> value = mNode.getValue();
            if (CollectionUtils.isEmpty(value)) {
                return null;
            }
            NodeTuple nodeTuple = value.get(0);
            ConfigMetadata configMetadata = new ConfigMetadata();
            SequenceNode sequenceNode = (SequenceNode) nodeTuple.getValueNode();
            if (CollectionUtils.isEmpty(sequenceNode.getValue())) {
                return configMetadata;
            }
            
            List<ConfigMetadata.ConfigExportItem> exportItems =
                sequenceNode.getValue().stream().map(itemValue -> {

View on GitHub (pinned to 9b989acdf1)