{"record":{"id":"66d99a54aa3429cd","repo":"Tencent/WeKnora","slug":"grpc-listengines-failed-w","errorCode":null,"errorMessage":"gRPC ListEngines failed: %w","messagePattern":"gRPC ListEngines failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/docparser/grpc_parser.go","lineNumber":241,"sourceCode":"\t\t\t\tStorageKey:  img.GetStorageKey(),\n\t\t\t\tImageData:   img.GetImageData(),\n\t\t\t})\n\t\t}\n\t}\n\treturn result, nil\n}\n\nfunc (p *GRPCDocumentReader) ListEngines(ctx context.Context, overrides map[string]string) ([]types.ParserEngineInfo, error) {\n\tp.mu.RLock()\n\tclient := p.client\n\tp.mu.RUnlock()\n\tif client == nil {\n\t\treturn nil, errNotConnected\n\t}\n\n\tresp, err := client.ListEngines(ctx, &proto.ListEnginesRequest{ConfigOverrides: overrides})\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"gRPC ListEngines failed: %w\", err)\n\t}\n\n\tresult := make([]types.ParserEngineInfo, 0, len(resp.GetEngines()))\n\tfor _, e := range resp.GetEngines() {\n\t\tresult = append(result, types.ParserEngineInfo{\n\t\t\tName:              e.GetName(),\n\t\t\tDescription:       e.GetDescription(),\n\t\t\tFileTypes:         e.GetFileTypes(),\n\t\t\tAvailable:         e.GetAvailable(),\n\t\t\tUnavailableReason: e.GetUnavailableReason(),\n\t\t})\n\t}\n\treturn result, nil\n}\n","sourceCodeStart":223,"sourceCodeEnd":256,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/docparser/grpc_parser.go#L223-L256","documentation":"ListEngines wraps any error from the unary ListEngines RPC with 'gRPC ListEngines failed: %w'. This RPC asks the docreader which parser engines it offers (names, file types, availability). The wrapped error is the raw gRPC failure: transport problem, server error, deadline, or auth rejection. If the client was never connected, errNotConnected is returned instead.","triggerScenarios":"Calling GRPCDocumentReader.ListEngines while the docreader gRPC server is unreachable, returns a gRPC error (Unavailable, Internal, DeadlineExceeded, PermissionDenied), the context is cancelled/times out, or auth/TLS credentials are rejected on the channel.","commonSituations":"docreader service not deployed or scaled to zero; wrong DOCTEAM/docreader address in configuration so DNS resolution or connection fails; environment timeout too short when engine discovery is slow (e.g. engines lazily initializing); token auth misconfigured after rotating secrets.","solutions":["Unwrap the error and inspect the gRPC status code (status.Convert) to distinguish Unavailable (connectivity) from PermissionDenied (auth)","Verify the docreader service is running and the configured address resolves and is reachable (grpcurl -plaintext addr list)","Increase the context deadline for engine listing on slow/cold-start deployments","Check auth/TLS env variables consumed by docclient.LoadAuthConfigFromEnv match the server configuration","Retry with backoff for transient Unavailable codes"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if !reader.IsConnected() {\n    return fmt.Errorf(\"docreader gRPC client not connected; check DOCREADER address config\")\n}","typeGuard":null,"tryCatchPattern":"var engines []types.ParserEngineInfo\nvar lastErr error\nfor attempt := 0; attempt < 3; attempt++ {\n    engines, lastErr = reader.ListEngines(ctx, overrides)\n    if lastErr == nil {\n        break\n    }\n    if st, ok := status.FromError(errors.Unwrap(lastErr)); ok && st.Code() == codes.Unavailable {\n        time.Sleep(time.Duration(1<<attempt) * time.Second) // backoff\n        continue\n    }\n    break // non-transient: don't retry\n}\nif lastErr != nil {\n    return fmt.Errorf(\"list engines: %w\", lastErr)\n}","preventionTips":["Verify docreader deployment health before engine discovery (readiness probe / IsConnected)","Configure an adequate context timeout for cold-start engine initialization","Keep auth/TLS env config for the docreader channel in sync with the server","Retry only transient codes (Unavailable, DeadlineExceeded) with exponential backoff"],"tags":["grpc","rpc-failure","service-discovery","docparser"],"backgroundTag":"grpc-unary-call-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}