istio/istio · error

request not successful %s

Error message

request not successful %s

What it means

ControlzClient.GetScopes performs a plain HTTP GET against istiod's ControlZ monitoring endpoint. If the response status is anything but 200 OK (404 wrong path, 503 while istiod starts, 500 on internal error, 401/403 behind auth), the body is discarded and this error with the HTTP status line is returned. All istioctl admin log read/write flows go through it.

Source

Thrown at istioctl/pkg/admin/istiodconfig.go:346

		scopeInfos = append(scopeInfos, si)
	}
	return scopeInfos, nil
}

type ControlzClient struct {
	baseURL    *url.URL
	httpClient *http.Client
}

func (c *ControlzClient) GetScopes() ([]*ScopeInfo, error) {
	var scopeInfos []*ScopeInfo
	resp, err := c.httpClient.Get(c.baseURL.String())
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("request not successful %s", resp.Status)
	}

	err = json.NewDecoder(resp.Body).Decode(&scopeInfos)
	if err != nil {
		return nil, fmt.Errorf("cannot deserialize response %s", err)
	}
	return scopeInfos, nil
}

func (c *ControlzClient) PutScope(scope *ScopeInfo) error {
	var jsonScopeInfo bytes.Buffer
	err := json.NewEncoder(&jsonScopeInfo).Encode(scope)
	if err != nil {
		return fmt.Errorf("cannot serialize scope %+v", *scope)
	}
	req, err := http.NewRequest(http.MethodPut, c.baseURL.String()+"/"+scope.Name, &jsonScopeInfo)
	if err != nil {
		return err

View on GitHub (pinned to 8dc789c5cf)

Solutions

  1. Confirm the ControlZ URL and port (default monitoring port 15014) match your istiod
  2. Curl the endpoint directly to see the raw status: curl -v http://<istiod>:15014/<scopes-path>
  3. Exclude istiod from sidecar injection / ensure no auth proxy sits in front of the monitoring port
  4. Retry once istiod reports Ready; if 404 persists, align istioctl and istiod versions

Example fix

curl -v http://istiod.istio-system.svc:15014/logging/scopes   # verify 200 before istioctl
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the ControlZ URL and reachability before issuing commands
u, err := url.Parse(controlzAddr)
if err != nil || u.Scheme != "http" && u.Scheme != "https" {
    return fmt.Errorf("invalid controlz address %q", controlzAddr)
}
resp, err := http.Get(u.String())
if err == nil {
    defer resp.Body.Close()
    if resp.StatusCode != http.StatusOK {
        return fmt.Errorf("controlz returned %s", resp.Status)
    }
}

Try / catch

scopes, err := client.GetScopes()
if err != nil {
    var se *url.Error
    if errors.As(err, &se) {
        // transport failure: retry with backoff
    } else if strings.Contains(err.Error(), "request not successful") {
        // HTTP-level: inspect status, do not blind-retry 4xx
    }
    return nil, err
}

Prevention

When it happens

Trigger: Hitting a ControlZ base URL where the scopes route does not exist (path/URL misconfigured in the client flags); istiod returning 503 during startup or shutdown; an intermediary (ingress, service mesh sidecar on istiod itself, auth proxy) rewriting or rejecting the request.

Common situations: istiod with sidecar injection enabled in istio-system so the request gets mTLS-intercepted; API-server proxy paths that strip routes; version skew where istioctl expects an endpoint shape istiod does not serve.

Related errors


AI-assisted analysis of istio/istio@8dc789c5cf (2026-08-15). Data as JSON: /api/errors/412d7a040681f9e1. Report an issue: GitHub.