yudaocode/SpringBoot-Labs · error · IllegalStateException

获取不到实例

Error message

获取不到实例

What it means

The labx-27 Spring Cloud Consul discovery consumer throws IllegalStateException("获取不到实例") when DiscoveryClient.getInstances("demo-provider") returns an empty list — Consul's catalog has no healthy instances registered under that name. Consul registers services with health checks (default TTL/HTTP per config); an instance that fails its health check is reported with a critical status, and Spring Cloud's Consul catalog query filters to passing instances by default. So this error arises both when the provider never registered and when it registered but its health check went critical — a distinction from plain Eureka lease semantics.

Source

Thrown at labx-27/labx-27-sc-consul-discovery-demo01-consumer/src/main/java/cn/iocoder/springcloud/labx27/consuldemo/consumer/DemoConsumerApplication.java:59

        private RestTemplate restTemplate;
        @Autowired
        private LoadBalancerClient loadBalancerClient;

        @GetMapping("/hello")
        public String hello(String name) {
            // 获得服务 `demo-provider` 的一个实例
            ServiceInstance instance;
            if (true) {
                // 获取服务 `demo-provider` 对应的实例列表
                List<ServiceInstance> instances = discoveryClient.getInstances("demo-provider");
                // 选择第一个
                instance = instances.size() > 0 ? instances.get(0) : null;
            } else {
                instance = loadBalancerClient.choose("demo-provider");
            }
            // 发起调用
            if (instance == null) {
                throw new IllegalStateException("获取不到实例");
            }
            String targetUrl = instance.getUri() + "/echo?name=" + name;
            String response = restTemplate.getForObject(targetUrl, String.class);
            // 返回结果
            return "consumer:" + response;
        }

    }

}

View on GitHub (pinned to 6c12efaed0)

Solutions

  1. Open the Consul UI (http://localhost:8500) and check the 'demo-provider' service: no service listed → start the demo provider; listed but red/critical → fix its health check (dependency/endpoint) so it turns green.
  2. Confirm the provider's spring.application.name equals demo-provider exactly and both apps use the same spring.cloud.consul.host/port.
  3. Start Consul in dev mode first (consul agent -dev), then the provider, wait for its check to pass, then the consumer call.
  4. If health-check strictness is unwanted in a demo, set spring.cloud.consul.discovery.register-health-check=false or configure queryOptions to skip checks, then retry.
  5. Handle the empty list explicitly (503 + message) or fall back to LoadBalancerClient.choose with a null check.

Example fix

// before
List<ServiceInstance> instances = discoveryClient.getInstances("demo-provider");
instance = instances.size() > 0 ? instances.get(0) : null;
if (instance == null) {
    throw new IllegalStateException("获取不到实例");
}

// after — explicit empty handling referencing Consul health
List<ServiceInstance> instances = discoveryClient.getInstances("demo-provider");
if (instances.isEmpty()) {
    throw new IllegalStateException(
        "获取不到实例: no passing Consul instances for 'demo-provider'; " +
        "check http://localhost:8500 for registration and health status");
}
ServiceInstance instance = instances.get(0);
Defensive patterns

Strategy: validation

Validate before calling

List<ServiceInstance> instances = discoveryClient.getInstances("demo-provider");
if (instances.isEmpty()) {
    // includes 'registered but health check critical' cases, since queries filter to passing
    throw new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE,
        "demo-provider 无健康实例, 请检查 Consul UI (http://localhost:8500)");
}
ServiceInstance instance = instances.get(0);

Type guard

boolean consulHasPassingInstance(DiscoveryClient dc, String service) {
    List<ServiceInstance> list = dc.getInstances(service);
    return list != null && !list.isEmpty();
}

Try / catch

catch (IllegalStateException e) {
    if ("获取不到实例".equals(e.getMessage())) {
        // likely health-check critical or not yet registered: 503 + hint
        return ResponseEntity.status(503)
            .body("demo-provider not passing Consul health checks; check consul UI");
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling /echo when: the Consul provider app is not running or never registered (missing spring-cloud-starter-consul-discovery); spring.application.name ≠ 'demo-provider'; Consul agent not started (default localhost:8500) or consumer's spring.cloud.consul.host/port point to the wrong agent; the provider registered but its health check is critical so the passing-only query yields nothing; provider is mid-startup and registration/health-check propagation has not completed.

Common situations: Consul agent (dev mode: consul agent -dev) not running before the apps; health-check failures (e.g. the default /actuator/health endpoint unavailable because management deps missing, or a misconfigured spring.cloud.consul.discovery.health-check-path); name mismatches between the getInstances literal and provider's spring.application.name; Docker/remote Consul where host/port config is stale; querying a catalog in a different Consul datacenter.

Related errors


AI-assisted analysis of yudaocode/SpringBoot-Labs@6c12efaed0 (2026-08-14). Data as JSON: /api/errors/59946fd72476007a. Report an issue: GitHub.