Tencent/WeKnora · error

failed to delete chunks: %w

Error message

failed to delete chunks: %w

What it means

executeFAQImport wraps errors from chunkRepo.DeleteChunks when bulk-deleting chunks that must be removed or replaced in replace-mode import. Deletion happens before vector cleanup, so a failure here leaves old vectors in the index but no DB chunks. The cause is the repository/DB error preserved by %w.

Source

Thrown at internal/application/service/knowledge_faq_import.go:1420

		// Replace模式:计算需要删除、创建、更新的条目
		entriesToProcess, chunksToDelete, skippedCount, err = s.calculateReplaceOperations(
			ctx,
			tenantID,
			faqKnowledge.ID,
			payload.Entries,
		)
		if err != nil {
			return fmt.Errorf("failed to calculate replace operations: %w", err)
		}

		// 删除需要删除的chunks(包括需要更新的旧chunks)
		if len(chunksToDelete) > 0 {
			chunkIDsToDelete := make([]string, 0, len(chunksToDelete))
			for _, chunk := range chunksToDelete {
				chunkIDsToDelete = append(chunkIDsToDelete, chunk.ID)
			}
			if err := s.chunkRepo.DeleteChunks(ctx, tenantID, chunkIDsToDelete); err != nil {
				return fmt.Errorf("failed to delete chunks: %w", err)
			}
			// 删除索引
			if err := s.deleteFAQChunkVectors(ctx, kb, faqKnowledge, chunksToDelete); err != nil {
				return fmt.Errorf("failed to delete chunk vectors: %w", err)
			}
			logger.Infof(ctx, "FAQ import task %s: deleted %d chunks (including updates)", taskID, len(chunksToDelete))
		}
	} else {
		// Append 模式(智能合并):标准问已存在的条目走 merge ops,其余作为新建。
		var mergeOps []faqMergeOperation
		entriesToProcess, mergeOps, skippedCount, err = s.calculateAppendOperations(ctx, tenantID, kb.ID, payload.Entries)
		if err != nil {
			return fmt.Errorf("failed to calculate append operations: %w", err)
		}

		if len(mergeOps) > 0 {
			mergedCount, mergeErr := s.executeFAQMergeOperations(ctx, taskID, kb, faqKnowledge, embeddingModel, indexMode, mergeOps, progress)
			if mergeErr != nil {

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the wrapped cause (constraint violation vs connectivity vs timeout)
  2. Retry the import; DeleteChunks is usually safe to re-attempt as part of the idempotent replace flow
  3. Check for FK constraints/locks on chunks and chunk batch size limits
  4. Serialize imports per knowledge base to avoid concurrent-delete deadlocks

Example fix

// before
if err := s.chunkRepo.DeleteChunks(ctx, tenantID, chunkIDsToDelete); err != nil {
	return fmt.Errorf("failed to delete chunks: %w", err)
}
// after
if err := s.chunkRepo.DeleteChunks(ctx, tenantID, chunkIDsToDelete); err != nil {
	return fmt.Errorf("failed to delete %d chunks (task %s): %w", len(chunkIDsToDelete), taskID, err)
}
Defensive patterns

Strategy: retry

Validate before calling

// Preflight: ensure no concurrent task is mutating the same knowledge base
locked, err := acquireImportLock(ctx, redisClient, "faq-import:"+kbID, ttl)
if err != nil || !locked {
	return fmt.Errorf("another FAQ import is running for this knowledge base")
}
defer releaseImportLock(redisClient, "faq-import:"+kbID)

Try / catch

err := runReplaceImport(ctx, req)
if err != nil && strings.Contains(err.Error(), "failed to delete chunks") {
	if errors.Is(err, context.DeadlineExceeded) || isDeadlock(err) {
		return retryWithBackoff(3, runReplaceImport, ctx, req)
	}
	return err // constraint errors need manual/data-model fix
}
return err

Prevention

When it happens

Trigger: Replace-mode import computes a non-empty chunksToDelete list; DeleteChunks fails due to DB outage, transaction/lock timeout, foreign-key constraint, or context cancellation.

Common situations: Deadlocks with concurrent imports on the same knowledge base; FK constraints referencing chunk IDs; DB connection drop mid-batch-delete; overly large batch exceeding statement limits.

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/9b8cb0291f45b97a. Report an issue: GitHub.