apache/dubbo · error · UnsupportedOperationException

setServiceModel is forbidden for ServiceAddressURL

Error message

setServiceModel is forbidden for ServiceAddressURL

What it means

UnsupportedOperationException thrown by ServiceAddressURL.setServiceModel() for the same architectural reason as setScopeModel(): ServiceAddressURL delegates getServiceModel() to its wrapped consumerURL, and the service model is owned by the consumer side, not the address. Mutating it on the address URL is forbidden. Callers must operate on the consumerURL directly.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/url/component/ServiceAddressURL.java:225

    @Override
    public ScopeModel getScopeModel() {
        return consumerURL.getScopeModel();
    }

    @Override
    public ServiceModel getServiceModel() {
        return consumerURL.getServiceModel();
    }

    @Override
    public URL setScopeModel(ScopeModel scopeModel) {
        throw new UnsupportedOperationException("setScopeModel is forbidden for ServiceAddressURL");
    }

    @Override
    public URL setServiceModel(ServiceModel serviceModel) {
        throw new UnsupportedOperationException("setServiceModel is forbidden for ServiceAddressURL");
    }

    /**
     * ignore consumer url compare.
     * It's only meaningful for comparing two address urls related to the same consumerURL.
     *
     * @param obj
     * @return
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof ServiceAddressURL)) {

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Do not call setServiceModel() on ServiceAddressURL — set it on the consumer URL via getConsumerURL().
  2. Guard the call with an instanceof check and redirect to the consumer URL for ServiceAddressURL instances.
  3. Audit custom extension code for blanket URL mutation and make it respect the ServiceAddressURL contract.

Example fix

// before — generic mutation fails on ServiceAddressURL
url.setServiceModel(serviceModel); // throws if url is ServiceAddressURL

// after — set on the appropriate URL
if (url instanceof ServiceAddressURL) {
    ((ServiceAddressURL) url).getConsumerURL().setServiceModel(serviceModel);
} else {
    url.setServiceModel(serviceModel);
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Check URL type before calling setServiceModel
if (url instanceof ServiceAddressURL) {
    ((ServiceAddressURL) url).getConsumerURL().setServiceModel(serviceModel);
} else {
    url.setServiceModel(serviceModel);
}

Type guard

public static boolean isMutableServiceModel(URL url) {
    return !(url instanceof ServiceAddressURL);
}

Try / catch

try {
    url.setServiceModel(serviceModel);
} catch (UnsupportedOperationException e) {
    if (e.getMessage().contains("forbidden for ServiceAddressURL")) {
        if (url instanceof ServiceAddressURL) {
            ((ServiceAddressURL) url).getConsumerURL().setServiceModel(serviceModel);
        }
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling setServiceModel() on a ServiceAddressURL instance. This URL type is created internally during provider address resolution. Framework or application code that generically sets the service model on any URL reference will encounter this if the URL is a ServiceAddressURL.

Common situations: Generic URL manipulation code in custom filters, SPI extensions, or interceptors that calls setServiceModel() without type discrimination; Dubbo 2.x-to-3.x migration where address URLs became immutable for service model; code that walks URL chains and tries to set properties uniformly.

Understand the failure class

Related errors


AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14). Data as JSON: /api/errors/229265c1243f6168. Report an issue: GitHub.