{"record":{"id":"197aaddfc4ca6b9b","repo":"Tencent/WeKnora","slug":"invalid-search-result-format","errorCode":null,"errorMessage":"invalid search result format","messagePattern":"invalid search result format","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/repository/retriever/elasticsearch/v7/repository.go","lineNumber":1099,"sourceCode":"\tdefer response.Body.Close()\n\n\tif response.IsError() {\n\t\tlog.Errorf(\"[ElasticsearchV7] Failed to query source index data: %s\", response.String())\n\t\treturn nil, fmt.Errorf(\"failed to query source index data: %s\", response.String())\n\t}\n\n\t// 解析搜索结果\n\tvar searchResult map[string]interface{}\n\tif err := json.NewDecoder(response.Body).Decode(&searchResult); err != nil {\n\t\tlog.Errorf(\"[ElasticsearchV7] Failed to parse query result: %v\", err)\n\t\treturn nil, err\n\t}\n\n\t// 提取结果列表\n\thitsObj, ok := searchResult[\"hits\"].(map[string]interface{})\n\tif !ok {\n\t\tlog.Errorf(\"[ElasticsearchV7] Invalid search result format: 'hits' object missing\")\n\t\treturn nil, fmt.Errorf(\"invalid search result format\")\n\t}\n\n\thitsList, ok := hitsObj[\"hits\"].([]interface{})\n\tif !ok || len(hitsList) == 0 {\n\t\tif from == 0 {\n\t\t\tlog.Warnf(\"[ElasticsearchV7] No source index data found\")\n\t\t}\n\t\treturn []interface{}{}, nil\n\t}\n\n\treturn hitsList, nil\n}\n\n// processSourceBatch processes a batch of source data and creates index information\nfunc (e *elasticsearchRepository) processSourceBatch(ctx context.Context,\n\thitsList []interface{},\n\tsourceToTargetKBIDMap map[string]string,\n\tsourceToTargetChunkIDMap map[string]string,","sourceCodeStart":1081,"sourceCodeEnd":1117,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/repository/retriever/elasticsearch/v7/repository.go#L1081-L1117","documentation":"In CopyIndices' querySourceBatch, the raw search response map is expected to contain a nested 'hits' object. If the response lacks that shape (or it is not a map), the code logs 'Invalid search result format: hits object missing' and returns this error. It means Elasticsearch responded but not with the expected search-result JSON structure.","triggerScenarios":"searchResult[\"hits\"] fails the map[string]interface{} type assertion — e.g. an error/ack response, an empty body, or a proxy-mangled response passed as the search result.","commonSituations":"ES node returning an error JSON (no hits field) during index copy/migration; wrong endpoint or security interceptor altering the response; version mismatch where the client hit a non-search API; network middleware returning an HTML error page decoded into a map without 'hits'.","solutions":["Log/inspect the full raw response body to see what Elasticsearch actually returned","Check the cluster is healthy and the endpoint is the _search API (GET/POST <index>/_search) not another route","Verify credentials and that no proxy/WAF is rewriting the response","Confirm ES client/server major versions match (this is the v7 repository); retry CopyIndices once the cluster is stable"],"exampleFix":"// before\nresp, err := es.PerformRequest(...)\nsearchResult := decode(resp)\n// after: check HTTP status and errors first\nif resp.StatusCode != 200 {\n    return nil, fmt.Errorf(\"search failed: status %d body %s\", resp.StatusCode, string(resp.Body))\n}\nsearchResult := decode(resp)","handlingStrategy":"try-catch","validationCode":"resp, err := client.Search(ctx, req)\nif err != nil { return err }\nif resp.StatusCode != 200 || !json.Valid(resp.Body) {\n    return fmt.Errorf(\"bad ES response: status=%d\", resp.StatusCode)\n}\nvar probe struct{ Hits map[string]json.RawMessage `json:\"hits\"` }\nif json.Unmarshal(resp.Body, &probe) != nil || probe.Hits == nil {\n    return fmt.Errorf(\"response missing hits object\")\n}","typeGuard":"func hasValidHitsShape(searchResult map[string]interface{}) bool {\n    _, ok := searchResult[\"hits\"].(map[string]interface{})\n    return ok\n}","tryCatchPattern":"batch, err := querySourceBatch(ctx, index, from, size)\nif err != nil {\n    if strings.Contains(err.Error(), \"invalid search result format\") {\n        logRawResponse(lastResponse) // diagnose actual ES output before retry\n    }\n}","preventionTips":["Check HTTP status and decode ES error bodies before interpreting results","Pin ES client and server to the same major version (v7 repo ↔ v7 cluster)","Ensure no proxy/WAF rewrites JSON responses","Add integration tests that assert the hits shape for CopyIndices"],"tags":["go","elasticsearch","migration","response-parsing"],"backgroundTag":"invalid-es-response-shape","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}