{"record":{"id":"eab8cd31e3426f80","repo":"Tencent/WeKnora","slug":"service-unreachable-w","errorCode":null,"errorMessage":"service unreachable: %w","messagePattern":"service unreachable: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/weknoracloud.go","lineNumber":81,"sourceCode":"\t\treturn fmt.Errorf(\"create verification request failed: %w\", err)\n\t}\n\n\trequestID := fmt.Sprintf(\"verify-%d\", time.Now().UnixNano())\n\tsignHeaders := modelsutils.Sign(appID, appSecret, requestID, \"{}\")\n\tfor k, v := range signHeaders {\n\t\treq.Header.Set(k, v)\n\t}\n\n\tlogger.Infof(ctx, \"credential verification request: method=GET url=%s app_id=%s request_id=%s \",\n\t\thealthURL, appID, requestID)\n\n\tclientCfg := utils.DefaultSSRFSafeHTTPClientConfig()\n\tclientCfg.Timeout = 10 * time.Second\n\tclient := utils.NewSSRFSafeHTTPClient(clientCfg)\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\tlogger.Warnf(ctx, \"credential verification HTTP failed: url=%s err=%v\", healthURL, err)\n\t\treturn fmt.Errorf(\"service unreachable: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {\n\t\treturn fmt.Errorf(\"invalid APPID or APPSECRET (HTTP %d)\", resp.StatusCode)\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"invalid response status code: %d\", resp.StatusCode)\n\t}\n\treturn nil\n}\n\n// CheckStatus 检查 WeKnoraCloud 凭证是否可正常解密\nfunc (s *weKnoraCloudService) CheckStatus(ctx context.Context) (*types.WeKnoraCloudStatusResult, error) {\n\ttenantID := types.MustTenantIDFromContext(ctx)\n\n\ttenant, err := s.tenantRepo.GetTenantByID(ctx, tenantID)\n\tif err != nil || tenant == nil {","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/weknoracloud.go#L63-L99","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nclientCfg.Timeout = 10 * time.Second // hard-coded\n// after\n// keep 10s, but surface retries for transient errors\nfor attempt := 0; attempt < 3; attempt++ {\n\tif err := s.verifyCredentials(ctx, appID, appSecret); err == nil || !errors.Is(err, context.DeadlineExceeded) {\n\t\treturn err\n\t}\n\ttime.Sleep(time.Second)\n}\nreturn nil","handlingStrategy":"retry","validationCode":"conn, err := net.DialTimeout(\"tcp\", host+\":443\", 5*time.Second)\nif err != nil {\n\treturn fmt.Errorf(\"WeKnora Cloud unreachable before credential save: %w\", err)\n}\nconn.Close()","typeGuard":null,"tryCatchPattern":"err := svc.SaveCredentials(ctx, appID, appSecret)\nif err != nil && strings.Contains(err.Error(), \"service unreachable\") {\n\t// transient: retry with backoff, then report outage\n\treturn retryWithBackoff(3, 2*time.Second, func() error {\n\t\treturn svc.SaveCredentials(ctx, appID, appSecret)\n\t})\n}","preventionTips":["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."],"tags":["network","weknora-cloud","http","timeout","ssrf"],"backgroundTag":"service-unreachable","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}