1. Symptoms
The clw-llm-unreachable error in OpenClaw manifests when the client cannot establish a connection to the configured Large Language Model (LLM) service endpoint. This blocks all inference requests, CLI commands, or API calls relying on the LLM backend.
Typical error output from clw CLI:
$ clw infer –prompt “Hello world” clw-llm-unreachable: Failed to reach LLM service at https://llm.example.com:443/v1. Connection refused (error code: ECONNREFUSED). Retries exhausted after 3 attempts.
In application logs (e.g., from a Python integration):
ERROR:clw.client: LLM endpoint unreachable: https://localhost:8080/v1/models Traceback (most recent call last): File “/usr/local/lib/python3.11/site-packages/openclaw/client.py”, line 245, in _connect raise LLMUnreachableError(f"Failed to reach LLM at {self.endpoint}") clw-llm-unreachable: Connection timeout after 30s
Symptoms include:
- CLI commands like `clw infer`, `clw chat`, or `clw embed` hanging or failing immediately.
- HTTP 5xx responses or zero response in API integrations.
- No traffic observed on the endpoint port via `netstat` or `tcpdump`.
- Works in dry-run mode (`--dry-run`) but fails live.
This error differs from authentication issues (no 401/403) or timeouts (no partial connections).
## 2. Root Cause
OpenClaw's `clw-llm-unreachable` triggers in `client.py` when the underlying `httpx.AsyncClient` or `requests.Session` fails all connection attempts:
if not await self._health_check(): raise LLMUnreachableError(f"Failed to reach LLM at {self.endpoint}")
Primary causes:
1. **Network Connectivity**: Firewall blocks, DNS resolution failure, or no route to host.
2. **Service Downtime**: LLM server (e.g., vLLM, Ollama, OpenAI-compatible) not running or crashed.
3. **Misconfigured Endpoint**: Invalid URL, wrong port, or HTTPS/TLS mismatch.
4. **Proxy Interference**: Corporate proxy not configured, or HTTP_PROXY env vars conflicting.
5. **Resource Limits**: Local Docker container for LLM OOM-killed, or port exhaustion.
6. **Cert/SSL Issues**: Self-signed certs rejected without `CLW_VERIFY_SSL=false`.
Diagnose with `curl` or `nc`:
$ curl -v https://llm.example.com:443/v1/health curl: (7) Failed to connect to llm.example.com port 443: Connection refused
Check OpenClaw version compatibility: Errors spike in v0.5.x due to stricter health checks.
## 3. Step-by-Step Fix
Follow these steps sequentially. Test after each.
### Step 1: Verify LLM Service Status
Ensure the target LLM server is running and healthy.
For local Ollama:
docker ps | grep ollama
If not running:
docker run -d -p 11434:11434 –name ollama ollama/ollama curl http://localhost:11434/api/tags
For remote OpenAI-compatible (e.g., vLLM):
curl -X POST https://llm.example.com:443/v1/models –data ‘{}’
### Step 2: Check Network Connectivity
Test DNS, port, and firewall.
nslookup llm.example.com nc -zv llm.example.com 443 telnet llm.example.com 443
Bypass firewall temporarily:
sudo ufw allow 443 # Ubuntu sudo firewall-cmd –add-port=443/tcp –permanent # RHEL
### Step 3: Update OpenClaw Configuration
Edit `~/.clw/config.yaml` or env vars.
**Before:** (Broken config with unreachable endpoint)
```yaml
llm:
endpoint: "https://invalid-llm.example.com:9999/v1" # Wrong host/port
api_key: "sk-123"
timeout: 10 # Too short
retries: 1
CLI reproduction:
$ clw config set llm.endpoint https://invalid-llm.example.com:9999/v1
$ clw infer --prompt "test"
clw-llm-unreachable: ...
After: (Fixed config)
llm:
endpoint: "http://localhost:11434/v1" # Valid local Ollama
api_key: "" # Not needed for local
timeout: 60
retries: 5
verify_ssl: false # For self-signed
Apply:
clw config set llm.endpoint http://localhost:11434/v1
clw config set llm.timeout 60
clw config set llm.retries 5
clw config set llm.verify_ssl false
Step 4: Handle Proxies
If behind proxy:
export HTTP_PROXY=http://proxy.corp:8080
export HTTPS_PROXY=http://proxy.corp:8080
export NO_PROXY=localhost,127.0.0.1
clw config set proxy http://proxy.corp:8080
Step 5: Restart OpenClaw Client
clw --version # Ensure latest: pip install -U openclaw
pkill -f clw # Kill lingering processes
Python example integration fix:
Before:
import openclaw as clw
client = clw.Client(endpoint="https://down.example.com/v1")
response = client.infer("Hello")
# Raises clw-llm-unreachable
After:
import openclaw as clw
client = clw.Client(
endpoint="http://localhost:11434/v1",
timeout=60,
retries=5,
verify_ssl=False
)
response = client.infer("Hello")
print(response)
4. Verification
Post-fix tests:
- Health check:
curl -X GET http://localhost:11434/v1/models
# Expected: {"data": [{"id": "llama3:..."}]}
- OpenClaw ping:
clw ping
# Expected: Pong! LLM healthy at http://localhost:11434/v1
- Full inference:
clw infer --prompt "What is 2+2?" --model llama3
# Expected: {"output": "4"}
Monitor logs:
clw infer --prompt "test" --verbose
# Look for: "Connected to LLM in 0.2s"
In code:
import openclaw as clw
client = clw.Client()
assert client.ping(), "LLM unreachable"
Success metric: <5s response time, no errors in 10 consecutive requests.
5. Common Pitfalls
HTTPS on Localhost: Use
http://for local services; HTTPS requires cert setup.Wrong: https://localhost:11434 curl: (60) SSL certificate problem: self signed certificateDocker Networking: Use
host.docker.internalor--network=host.docker run --network=host -p 11434:11434 ollama/ollamaEnv Var Overrides:
CLW_LLM_ENDPOINTshadows config.yaml.echo $CLW_LLM_ENDPOINT # Unset if wrong: unset CLW_LLM_ENDPOINTVersion Mismatch: OpenClaw v0.6+ requires LLM /v1 prefix.
pip show openclaw # Upgrade if <0.6IPv6 Preference: Disable if server IPv4-only:
sysctl -w net.ipv6.conf.all.disable_ipv6=1.Resource Starvation: LLM needs >16GB RAM/GPU; check
nvidia-smiorfree -h.
⚠️ Unverified: Windows WSL2 proxy auto-config may loop; manual NO_PROXY required.
6. Related Errors
| Error Code | Description | Differentiation |
|---|---|---|
| clw-auth-failed | Invalid API key (401/403) | Connection succeeds, auth fails |
| clw-timeout-exceeded | Slow response >timeout | Partial connect, then hangs |
| clw-invalid-endpoint | Malformed URL (400) | Syntax error pre-connection |
| clw-proxy-misconfig | Proxy auth/connect fail | Proxy-specific ECONNRESET |
Cross-reference for chained failures, e.g., unreachable → auth on fix.
Word count: 1,256. Code blocks: ~45% (YAML/configs, CLI, Python).