{"record":{"id":"9835314668db7846","repo":"Tencent/WeKnora","slug":"credential-verification-failed-w","errorCode":null,"errorMessage":"credential verification failed: %w","messagePattern":"credential verification failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/weknoracloud.go","lineNumber":46,"sourceCode":"\t\ttenantRepo: tenantRepo,\n\t}\n}\n\nfunc IsWeKnoraCloudDocReaderAddr(addr string) bool {\n\treturn strings.TrimSuffix(strings.TrimSpace(addr), \"/\") == strings.TrimRight(provider.WeKnoraCloudBaseURL, \"/\")+\"/api/v1/doc/reader\"\n}\n\n// SaveCredentials 仅保存 APPID/APPSECRET 凭证，不自动创建模型\nfunc (s *weKnoraCloudService) SaveCredentials(ctx context.Context, appID, appSecret string) error {\n\tif appID == \"\" {\n\t\treturn fmt.Errorf(\"app_id is required\")\n\t}\n\tif appSecret == \"\" {\n\t\treturn fmt.Errorf(\"app_secret is required\")\n\t}\n\n\tif err := s.verifyCredentials(ctx, appID, appSecret); err != nil {\n\t\treturn fmt.Errorf(\"credential verification failed: %w\", err)\n\t}\n\n\ttenantID := types.MustTenantIDFromContext(ctx)\n\treturn s.updateTenantCredentials(ctx, tenantID, appID, appSecret)\n}\n\n// verifyCredentials 向 WeKnoraCloud /api/v1/health 发送带签名头的 GET。\n//\n// 注意：health 一般为探活接口，远端常不校验 APPID/SECRET 或签名；HTTP 200 通常只表示\n// 「网关/服务可达」，不能严格证明凭证有效。若需强校验，应改为调用必须鉴权的业务接口。\nfunc (s *weKnoraCloudService) verifyCredentials(ctx context.Context, appID, appSecret string) error {\n\tbaseURL := strings.TrimRight(provider.WeKnoraCloudBaseURL, \"/\")\n\thealthURL := baseURL + \"/api/v1/health\"\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, healthURL, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"create verification request failed: %w\", err)\n\t}","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/weknoracloud.go#L28-L64","documentation":"After basic field checks, SaveCredentials verifies the APPID/APPSECRET pair against the WeKnora Cloud health endpoint via verifyCredentials. If verification returns any error (bad request, unreachable service, bad credentials, bad status), it is wrapped as 'credential verification failed: %w' preserving the cause.","triggerScenarios":"SaveCredentials called with non-empty credentials that fail verification: http.NewRequestWithContext error, network/SSRF-safe client failure (service unreachable), HTTP 401/403, or non-200 status from the health endpoint.","commonSituations":"Typo'd APPID/APPSECRET; WeKnora Cloud instance down or wrong base URL; corporate proxy blocking outbound HTTPS; clock/signature mismatch if the Sign helper produces invalid headers.","solutions":["Inspect the wrapped %w cause in the error chain (errors.Unwrap / %v output) to see which sub-failure occurred.","Confirm APPID/APPSECRET are correct by re-entering them from the WeKnora Cloud console.","Verify provider.WeKnoraCloudBaseURL points at the correct reachable instance (curl the /api/v1/health path).","Check network egress/proxy rules allow the app to reach the cloud base URL.","If signature headers are involved, confirm server clocks are NTP-synced and the Sign helper matches the server's expected scheme."],"exampleFix":"// before\nif err := svc.SaveCredentials(ctx, appID, appSecret); err != nil { log.Println(err) }\n// after\nif err := svc.SaveCredentials(ctx, appID, appSecret); err != nil {\n\tlog.Printf(\"save failed: %v (cause: %v)\", err, errors.Unwrap(err))\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := svc.SaveCredentials(ctx, appID, appSecret); err != nil {\n\tvar cause error\n\tif errors.As(err, &cause) || (cause = errors.Unwrap(err)) != nil {\n\t\tswitch {\n\t\tcase strings.Contains(cause.Error(), \"unreachable\"):\n\t\t\t// network path\n\t\tcase strings.Contains(cause.Error(), \"invalid APPID\"):\n\t\t\t// credentials path\n\t\t}\n\t}\n\treturn err\n}","preventionTips":["Always log/unwrap the error chain, since this message hides the real cause.","Pre-test credentials against the health endpoint before calling SaveCredentials.","Confirm base URL and network egress are correct before diagnosing credentials.","Keep server clocks synced so signature headers validate."],"tags":["weknora-cloud","credentials","http","verification"],"backgroundTag":"credential-verification-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}