apache/skywalking · error · IllegalStateException

forward_failed

forward_failed

Error message

no admin channel to forward-target {mainAddress} (peer list out of sync?)

What it means

RuntimeRuleClusterClient.forwardToMain throws IllegalStateException (code forward_failed) when findChannelForAddress(mainAddress) returns null — the client has no cached admin gRPC channel to the node elected as 'main' for this rule operation. The message hints at the root cause: the OAP cluster peer list is out of sync with the address the coordinator handed out, so the forward target is unknown to the channel cache. This is a topology/consistency problem in the OAP cluster, not a rule-content problem.

Source

Thrown at oap-server/server-admin/runtime-rule/src/main/java/org/apache/skywalking/oap/server/receiver/runtimerule/cluster/RuntimeRuleClusterClient.java:266

     *
     * <p>Uses a longer deadline than Suspend / Resume because the forwarded workflow on the
     * main can include compile + DDL + persist which is orders of magnitude slower than a
     * bookkeeping broadcast. Caller supplies the deadline in ms so admin operations can
     * tune it independently of cluster-control fan-outs.
     *
     * @return the main's response. Never null on success; throws on transport failure so
     *         the caller can surface a clear diagnostic to the operator.
     */
    public ForwardResponse forwardToMain(final String mainAddress,
                                          final String operation,
                                          final String catalog, final String name,
                                          final byte[] body,
                                          final boolean allowStorageChange,
                                          final boolean forceReapply,
                                          final long deadlineMs) {
        final ManagedChannel channel = findChannelForAddress(mainAddress);
        if (channel == null) {
            throw new IllegalStateException(
                "no admin channel to forward-target " + mainAddress + " (peer list out of sync?)");
        }
        final RuntimeRuleClusterServiceGrpc.RuntimeRuleClusterServiceBlockingStub stub =
            RuntimeRuleClusterServiceGrpc.newBlockingStub(channel)
                                         .withDeadlineAfter(deadlineMs, TimeUnit.MILLISECONDS);
        return stub.forward(ForwardRequest.newBuilder()
            .setOperation(operation == null ? "" : operation)
            .setCatalog(catalog == null ? "" : catalog)
            .setName(name == null ? "" : name)
            .setBody(body == null ? ByteString.EMPTY : ByteString.copyFrom(body))
            .setAllowStorageChange(allowStorageChange)
            .setForceReapply(forceReapply)
            .setSenderNodeId(selfNodeId)
            .setIssuedAtMs(System.currentTimeMillis())
            .build());
    }

    /**

View on GitHub (pinned to 102af09b4a)

Solutions

  1. Trigger peer-list reconciliation: wait for the cluster register (ZooKeeper/K8s/Nacos) sync interval, or restart the affected OAP node to force a fresh view
  2. Verify every OAP node advertises a reachable address for the admin/cluster gRPC port (check cluster config: host binding vs container IP, NAT considerations)
  3. Check the target address in the message is actually one of your live OAP members — if it is stale, the coordinator's registration is the thing to fix
  4. Retry the rule operation after topology settles; forwarding is a client-side retryable action once the channel cache refreshes
Defensive patterns

Strategy: retry

Validate before calling

final ManagedChannel ch = client.peekChannelForAddress(mainAddress); // expose a peek variant
if (ch == null || ch.isShutdown()) { awaitPeerListSync(); then re-check; }

Try / catch

catch (IllegalStateException e) when 'no admin channel to forward-target': back off one peer-sync interval, then retry the forward — the channel cache repopulates from the reconciled peer list. Give up with an operator alert only after the topology has demonstrably settled.

Prevention

When it happens

Trigger: Calling a runtime-rule operation that must be forwarded to the elected main (install/update/delete with cluster coordination) when findChannelForAddress has no cached channel for mainAddress — e.g. the coordinator returned an address this node never built a channel to, or the channel cache was built before that member joined. Any forwardToMain(...) call in this state throws immediately, before the gRPC stub is even created.

Common situations: A node joined/left the cluster recently and stale members still hold the old peer list; Container/k8s environments where a pod's address changed (restart, reschedule) but the cluster register still advertises the old one; Clock or registration races during rolling restarts of the OAP cluster; Network policies blocking admin-port connections so the channel was never established

Related errors


AI-assisted analysis of apache/skywalking@102af09b4a (2026-08-14). Data as JSON: /api/errors/f95c891b5928255f. Report an issue: GitHub.