alibaba/nacos · error · IllegalArgumentException

Agent update input must not contain read-only projection fie

Error message

Agent update input must not contain read-only projection fields

What it means

An Agent replacement for metadata update must not include read-only server-managed projection fields: versionInfo, versionCatalog, metaVersion, createTime, or updateTime. These are derived and maintained by the server; accepting client values would corrupt version tracking and optimistic-concurrency semantics.

Source

Thrown at ai/src/main/java/com/alibaba/nacos/ai/service/agent/AgentPersistenceService.java:1090

            || version.getUpdateTime() != null) {
            throw new IllegalArgumentException(
                "Agent Version must not contain read-only projection fields");
        }
        if (preferredLatest != null && !version.getVersion().equals(preferredLatest)) {
            throw new IllegalArgumentException("preferredLatest must target the created Version");
        }
    }
    
    private void validateAgentUpdateInputs(Agent replacement) {
        if (replacement == null) {
            throw new IllegalArgumentException("Agent replacement must not be null");
        }
        AgentValidationUtils.validateNamespaceId(replacement.getNamespaceId());
        AgentValidationUtils.validateAgentName(replacement.getAgentName());
        if (replacement.getVersionInfo() != null || replacement.getVersionCatalog() != null
            || replacement.getMetaVersion() != null || replacement.getCreateTime() != null
            || replacement.getUpdateTime() != null) {
            throw new IllegalArgumentException(
                "Agent update input must not contain read-only projection fields");
        }
    }
    
    private Agent normalizeAgentUpdate(Agent source, Agent current) {
        Agent result = new Agent();
        result.setNamespaceId(source.getNamespaceId());
        result.setAgentName(source.getAgentName());
        result.setDisplayName(source.getDisplayName());
        result.setDescription(source.getDescription());
        result.setIconUrl(source.getIconUrl());
        result.setProvider(source.getProvider());
        result.setTags(source.getTags());
        result.setExtensions(source.getExtensions());
        result.setStatus(source.getStatus());
        result.setOwner(current.getOwner());
        result.setScope(current.getScope());
        result.setVersionInfo(current.getVersionInfo());

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Build the update Agent from scratch with only writable fields (namespaceId, agentName, displayName, description, iconUrl, provider, tags, extensions, status, owner, scope).
  2. Null out versionInfo, versionCatalog, metaVersion, createTime, updateTime on any Agent object before passing it to tryUpdateAgent.
  3. Use a dedicated AgentUpdateRequest/Form that only exposes writable fields.

Example fix

// before — full projection re-submitted as update
Agent replacement = fetchedAgent; // from GET response
replacement.setDisplayName("New Name");
persistenceService.tryUpdateAgent(replacement, current); // throws

// after — only writable fields
Agent replacement = new Agent();
replacement.setNamespaceId("public");
replacement.setAgentName("my-agent");
replacement.setDisplayName("New Name");
persistenceService.tryUpdateAgent(replacement, current);
Defensive patterns

Strategy: validation

Validate before calling

if (replacement.getVersionInfo() != null || replacement.getVersionCatalog() != null
    || replacement.getMetaVersion() != null || replacement.getCreateTime() != null
    || replacement.getUpdateTime() != null) {
    throw new IllegalArgumentException("Agent update must not include read-only fields");
}

Type guard

boolean hasNoReadOnlyFields(Agent a) {
    return a.getVersionInfo() == null && a.getVersionCatalog() == null
        && a.getMetaVersion() == null && a.getCreateTime() == null && a.getUpdateTime() == null;
}

Prevention

When it happens

Trigger: Calling tryUpdateAgent with an Agent whose getVersionInfo(), getVersionCatalog(), getMetaVersion(), getCreateTime(), or getUpdateTime() returns non-null. This happens when a client fetches an Agent via GET and re-submits the full object as an update payload.

Common situations: A client GETs an Agent, modifies displayName, and PUTs the entire object back including versionInfo and timestamps. A generic client SDK serializes all fields on update. A migration tool copies full projections between environments.

Related errors


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