{"record":{"id":"7e9a70ec566fde9c","repo":"Tencent/WeKnora","slug":"failed-to-index-chunk-w","errorCode":null,"errorMessage":"failed to index chunk: %w","messagePattern":"failed to index chunk: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/knowledge_faq.go","lineNumber":243,"sourceCode":"\t}\n\n\t// 保存chunk\n\tif err := s.chunkService.CreateChunks(ctx, []*types.Chunk{chunk}); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create chunk: %w\", err)\n\t}\n\n\t// 索引chunk：交互式创建给索引步骤设硬上限，避免 embedding 抖动把请求拖长\n\tindexCtx, cancelIndex := context.WithTimeout(ctx, faqCreateIndexBudget)\n\tindexErr := s.indexFAQChunks(indexCtx, kb, faqKnowledge, []*types.Chunk{chunk}, embeddingModel, true, false)\n\tcancelIndex()\n\tif indexErr != nil {\n\t\t// 如果索引失败，删除已创建的chunk。回滚失败会留下一条 stored 状态的\n\t\t// 残留：它不出现在列表里，却会被重复校验命中，因此必须告警而非静默。\n\t\tif delErr := s.chunkService.DeleteChunk(ctx, chunk.ID); delErr != nil {\n\t\t\tlogger.Errorf(ctx,\n\t\t\t\t\"CreateFAQEntry: rollback failed, chunk %s left in stored state: %v\", chunk.ID, delErr)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"failed to index chunk: %w\", indexErr)\n\t}\n\n\t// 更新chunk状态为已索引\n\tchunk.Status = int(types.ChunkStatusIndexed)\n\tif err := s.chunkService.UpdateChunk(ctx, chunk); err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to update chunk status: %w\", err)\n\t}\n\n\t// Build tag seq_id map for conversion\n\ttagSeqIDMap := make(map[string]int64)\n\tif chunk.TagID != \"\" {\n\t\ttag, tagErr := s.tagRepo.GetByID(ctx, tenantID, chunk.TagID)\n\t\tif tagErr == nil && tag != nil {\n\t\t\ttagSeqIDMap[tag.ID] = tag.SeqID\n\t\t}\n\t}\n\n\t// 转换为FAQEntry返回","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/knowledge_faq.go#L225-L261","documentation":"CreateFAQEntry indexes the chunk within a hard 5-second budget (faqCreateIndexBudget) by embedding it via indexFAQChunks; on failure it deletes the stored chunk (best-effort rollback) and returns this error. It means embedding/indexing failed or exceeded the 5s timeout, most often because the embedding backend is slow, degraded, or unreachable. Note the rollback may fail, leaving a stored-state chunk that still triggers duplicate checks.","triggerScenarios":"CreateFAQEntry where embedding takes >5s (embedding service latency/spike), the embedding API returns an error (quota, auth, model unavailable), the vector store write fails, or the parent context is cancelled.","commonSituations":"Overloaded or rate-limited embedding provider; wrong embedding API key/endpoint in environment config; network partition between WeKnora and the embedding/vector services; large FAQ answers inflating embedding time; upstream client retries piling concurrent creates.","solutions":["Check embedding service health/latency and API credentials; retry after the provider recovers.","Verify vector-store (e.g. Elasticsearch/Milvus) connectivity if the embedding call itself succeeded.","Look for rollback-failure warnings ('rollback failed, chunk ... left in stored state') and manually delete stored-state residue before retrying, or duplicates will be blocked.","For bulk work, use import/bulk APIs which keep the full retry budget instead of the 5s interactive cap.","Reduce FAQ answer size or switch to a faster/nearest embedding model."],"exampleFix":"// before: embedding provider misconfigured\n// EMBEDDING_API_KEY=\"\" (empty)\n// after: set valid credentials and verify before creating entries\nexport EMBEDDING_API_KEY=sk-...\ncurl -s $EMBEDDING_ENDPOINT/health  # must return 200 before retry","handlingStrategy":"retry","validationCode":"// verify embedding backend before creating entries\nresp, err := http.Get(os.Getenv(\"EMBEDDING_ENDPOINT\") + \"/health\")\nif err != nil || resp.StatusCode != 200 {\n\treturn errors.New(\"embedding service unhealthy; postpone FAQ creation\")\n}","typeGuard":null,"tryCatchPattern":"entry, err := svc.CreateFAQEntry(ctx, kbID, payload)\nif err != nil && strings.Contains(err.Error(), \"failed to index chunk\") {\n\tif errors.Is(err, context.DeadlineExceeded) {\n\t\t// embedding exceeded the 5s budget; retry after backend recovers\n\t\ttime.Sleep(5 * time.Second)\n\t\tentry, err = svc.CreateFAQEntry(ctx, kbID, payload)\n\t}\n\t// also check logs for 'rollback failed' and clean stored-state residue\n}","preventionTips":["Health-check the embedding service and vector store before bulk FAQ creation","Keep embedding API keys/quotas valid and monitor provider latency","After failures, sweep for stored-state residue chunks that block duplicate questions","Use bulk/import APIs for large batches; they keep the full retry budget","Do not wrap creates in tight client retries — concurrent creates pile up duplicates"],"tags":["embedding","timeout","indexing","faq","go"],"backgroundTag":"embedding-index-timeout","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}