{"record":{"id":"b9d5bb37db6d3e01","repo":"Tencent/WeKnora","slug":"panic-during-faq-import-v","errorCode":null,"errorMessage":"panic during FAQ import: %v","messagePattern":"panic during FAQ import: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/application/service/knowledge_faq_import.go","lineNumber":1369,"sourceCode":"// executeFAQImport 执行实际的FAQ导入逻辑\nfunc (s *knowledgeService) executeFAQImport(ctx context.Context, taskID string, kbID string,\n\tpayload *types.FAQBatchUpsertPayload, tenantID uint64, processedCount int,\n\tprogress *types.FAQImportProgress,\n) (err error) {\n\t// 保存知识库和embedding模型信息，用于清理索引\n\tvar kb *types.KnowledgeBase\n\tvar embeddingModel embedding.Embedder\n\ttotalEntries := len(payload.Entries) + processedCount\n\n\t// Recovery机制：如果发生任何错误或panic，回滚所有已创建的chunks和索引数据\n\tdefer func() {\n\t\t// 捕获panic\n\t\tif r := recover(); r != nil {\n\t\t\tbuf := make([]byte, 8192)\n\t\t\tn := runtime.Stack(buf, false)\n\t\t\tstack := string(buf[:n])\n\t\t\tlogger.Errorf(ctx, \"FAQ import task %s panicked: %v\\n%s\", taskID, r, stack)\n\t\t\terr = fmt.Errorf(\"panic during FAQ import: %v\", r)\n\t\t}\n\t}()\n\n\tkb, err = s.validateFAQKnowledgeBase(ctx, kbID)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tkb.EnsureDefaults()\n\n\t// 获取embedding模型，用于后续清理索引\n\tembeddingModel, err = s.modelService.GetEmbeddingModel(ctx, kb.EmbeddingModelID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get embedding model: %w\", err)\n\t}\n\tfaqKnowledge, err := s.ensureFAQKnowledge(ctx, tenantID, kb)\n\tif err != nil {\n\t\treturn err","sourceCodeStart":1351,"sourceCodeEnd":1387,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/knowledge_faq_import.go#L1351-L1387","documentation":"executeFAQImport wraps its body in a deferred recover(); if any code in the import panics (nil map write, nil pointer dereference, index out of range), the panic is converted into this error and assigned to the task result. It indicates a programming defect in the import path rather than an expected failure. The stack trace is logged with the task ID.","triggerScenarios":"Any panic inside executeFAQImport: e.g., chunk.FAQMetadata() returning unexpected data leading to nil dereference, malformed FAQMetadata map access, or a callee panicking on malformed payload entries.","commonSituations":"New FAQ metadata format or older chunk records lacking fields the code assumes; concurrent map write; regression introduced by a recent code change; unexpected nil from a repository returning (nil, nil).","solutions":["Find the panic value and stack trace in the logs (logged as 'FAQ import task %s panicked')","Fix the nil/nil assumptions or malformed metadata handling at the panic site","Add nil guards before calling FAQMetadata()/map lookups on chunk data","Add unit tests with legacy/malformed chunk records to cover the panic path"],"exampleFix":"// before\nfor _, chunk := range existingChunks {\n\tmeta, cErr := chunk.FAQMetadata()\n\tif cErr == nil {\n\t\tq := meta.StandardQuestion\n\t\tstdQToChunk[q] = chunk\n\t}\n}\n// after\nfor _, chunk := range existingChunks {\n\tif chunk == nil {\n\t\tcontinue\n\t}\n\tmeta, cErr := chunk.FAQMetadata()\n\tif cErr != nil || meta == nil || meta.StandardQuestion == \"\" {\n\t\tcontinue\n\t}\n\tstdQToChunk[meta.StandardQuestion] = chunk\n}","handlingStrategy":"try-catch","validationCode":"// Validate payload entries before execution to avoid panic-prone paths\nfor i, e := range payload.Entries {\n\tif e.StandardQuestion == \"\" {\n\t\treturn fmt.Errorf(\"entry %d: empty standard question\", i)\n\t}\n}\n","typeGuard":"func (c *types.Chunk) HasValidFAQMetadata() bool {\n\tif c == nil {\n\t\treturn false\n\t}\n\tmeta, err := c.FAQMetadata()\n\treturn err == nil && meta != nil && meta.StandardQuestion != \"\"\n}","tryCatchPattern":"err := ProcessFAQImport(ctx, taskID, kbID, payload)\nif err != nil && strings.HasPrefix(err.Error(), \"panic during FAQ import\") {\n\tlogger.Errorf(ctx, \"import panicked; task %s marked failed, report bug with stack trace\", taskID)\n\tmarkTaskFailed(taskID, err)\n\treturn err // do not auto-retry panics; fix code first\n}\nreturn err","preventionTips":["Never ignore (value, nil) returns from repositories — check for nil values even on nil error","Guard all FAQMetadata()/map lookups against nil and missing fields","Run go test -race and fuzz tests on import entry parsing","Keep the recover() wrapper but alert on it — panics should be treated as bugs"],"tags":["panic","faq-import","bug"],"backgroundTag":"panic-during-import","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}