Tencent/WeKnora · error
service unreachable: %w
Error message
service unreachable: %w
What it means
verifyCredentials executes the health-check request through an SSRF-safe HTTP client with a 10s timeout. Any transport-level failure (DNS failure, connection refused, TLS error, timeout) is logged and wrapped as 'service unreachable: %w'. The credentials were never validated because the request never got a response.
Source
Thrown at internal/application/service/weknoracloud.go:81
return fmt.Errorf("create verification request failed: %w", err)
}
requestID := fmt.Sprintf("verify-%d", time.Now().UnixNano())
signHeaders := modelsutils.Sign(appID, appSecret, requestID, "{}")
for k, v := range signHeaders {
req.Header.Set(k, v)
}
logger.Infof(ctx, "credential verification request: method=GET url=%s app_id=%s request_id=%s ",
healthURL, appID, requestID)
clientCfg := utils.DefaultSSRFSafeHTTPClientConfig()
clientCfg.Timeout = 10 * time.Second
client := utils.NewSSRFSafeHTTPClient(clientCfg)
resp, err := client.Do(req)
if err != nil {
logger.Warnf(ctx, "credential verification HTTP failed: url=%s err=%v", healthURL, err)
return fmt.Errorf("service unreachable: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
return fmt.Errorf("invalid APPID or APPSECRET (HTTP %d)", resp.StatusCode)
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("invalid response status code: %d", resp.StatusCode)
}
return nil
}
// CheckStatus 检查 WeKnoraCloud 凭证是否可正常解密
func (s *weKnoraCloudService) CheckStatus(ctx context.Context) (*types.WeKnoraCloudStatusResult, error) {
tenantID := types.MustTenantIDFromContext(ctx)
tenant, err := s.tenantRepo.GetTenantByID(ctx, tenantID)
if err != nil || tenant == nil {View on GitHub (pinned to 988cbb0330)
Solutions
- Curl the health endpoint from the same host: curl -v <baseURL>/api/v1/health to confirm reachability.
- Check the wrapped cause: DNS vs refused vs timeout tells you which layer is broken.
- Verify the SSRF-safe client's allowlist — internal/private addresses may be intentionally blocked; use the public endpoint or adjust policy.
- If timeouts are marginal, investigate network latency; the 10s budget is fixed in code.
- Confirm the WeKnora Cloud service is running and its port is exposed.
Example fix
// before
clientCfg.Timeout = 10 * time.Second // hard-coded
// after
// keep 10s, but surface retries for transient errors
for attempt := 0; attempt < 3; attempt++ {
if err := s.verifyCredentials(ctx, appID, appSecret); err == nil || !errors.Is(err, context.DeadlineExceeded) {
return err
}
time.Sleep(time.Second)
}
return nil Defensive patterns
Strategy: retry
Validate before calling
conn, err := net.DialTimeout("tcp", host+":443", 5*time.Second)
if err != nil {
return fmt.Errorf("WeKnora Cloud unreachable before credential save: %w", err)
}
conn.Close() Try / catch
err := svc.SaveCredentials(ctx, appID, appSecret)
if err != nil && strings.Contains(err.Error(), "service unreachable") {
// transient: retry with backoff, then report outage
return retryWithBackoff(3, 2*time.Second, func() error {
return svc.SaveCredentials(ctx, appID, appSecret)
})
} Prevention
- Monitor the WeKnora Cloud health endpoint from your infra.
- Understand the SSRF-safe client's address policy; don't point it at blocked private ranges.
- Set realistic expectations for the fixed 10s timeout in slow networks.
- Check DNS and firewall/egress rules when deploying to new environments.
- Alert on 'service unreachable' occurrences to catch outages early.
When it happens
Trigger: SaveCredentials -> verifyCredentials where the WeKnora Cloud host is down, the hostname doesn't resolve, the SSRF-safe client blocks a private/disallowed address, or the request exceeds the 10-second timeout.
Common situations: Wrong base URL pointing at a non-existent host; WeKnora Cloud service stopped; firewall/egress rules blocking the app; pointing at an internal IP that the SSRF-safe client deliberately refuses; slow network exceeding the 10s timeout.
Related errors
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/eab8cd31e3426f80.
Report an issue: GitHub.