Tencent/WeKnora · error

failed to set FAQ metadata

Error message

failed to set FAQ metadata: %w

What it means

CreateFAQEntry wraps errors from Chunk.SetFAQMetadata (internal/types/faq.go), which sanitizes the FAQ metadata and JSON-marshals it into the chunk, also computing a normalized ContentHash. This only fails when the FAQChunkMetadata cannot be JSON-encoded (e.g. unsupported field types), since nil handling is graceful. It means the FAQ payload could not be serialized into the chunk's Metadata column.

Solutions

  1. Inspect the wrapped json.Marshal error to find the offending field in FAQChunkMetadata.
  2. Validate that the FAQ payload contains only strings/numbers/bools for metadata fields before submission.
  3. Update or fix any custom import/migration code that constructs FAQChunkMetadata with non-JSON-serializable values.
  4. Ensure client SDK / API version matches the server's FAQChunkMetadata schema.

Example fix

// before
meta.Answer = someFuncRef // non-marshalable
chunk.SetFAQMetadata(meta)
// after
meta.Answer = "plain text answer"
if err := chunk.SetFAQMetadata(meta); err != nil {
	return nil, fmt.Errorf("invalid FAQ payload: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

// ensure payload fields are JSON-safe before calling the API
for _, q := range append(payload.SimilarQuestions, payload.OriginQuestion, payload.Answer) {
	if strings.ContainsAny(q, "\x00") {
		return errors.New("FAQ payload contains non-text control bytes")
	}
}
if _, err := json.Marshal(payload); err != nil {
	return fmt.Errorf("payload not serializable: %w", err)
}

Try / catch

entry, err := svc.CreateFAQEntry(ctx, kbID, payload)
if err != nil && strings.Contains(err.Error(), "failed to set FAQ metadata") {
	return nil, fmt.Errorf("FAQ payload cannot be stored as metadata; check for non-JSON-serializable fields: %w", err)
}

Prevention

When it happens

Trigger: A FAQChunkMetadata containing values that fail json.Marshal (e.g. channels, funcs, or cyclic/invalid structures introduced programmatically, typically via migration/import code paths constructing metadata manually) passed into CreateFAQEntry's internal meta.

Common situations: Custom import/migration tooling building FAQChunkMetadata with non-marshalable fields; a version change to FAQChunkMetadata adding an unsupported type; corrupt payloads crafted by API callers that survive sanitization but break marshaling.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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

Appendix: source

Thrown at internal/application/service/knowledge_faq.go:224

	chunk := &types.Chunk{
		ID:              uuid.New().String(),
		TenantID:        tenantID,
		KnowledgeID:     faqKnowledge.ID,
		KnowledgeBaseID: kb.ID,
		Content:         buildFAQChunkContent(meta, indexMode),
		IsEnabled:       isEnabled,
		Flags:           flags,
		ChunkType:       types.ChunkTypeFAQ,
		TagID:           tagID, // 使用解析后的 TagID
		Status:          int(types.ChunkStatusStored),
	}
	// 如果指定了 ID(用于数据迁移),设置 SeqID
	if payload.ID != nil && *payload.ID > 0 {
		chunk.SeqID = *payload.ID
	}

	if err := chunk.SetFAQMetadata(meta); err != nil {
		return nil, fmt.Errorf("failed to set FAQ metadata: %w", err)
	}

	// 保存chunk
	if err := s.chunkService.CreateChunks(ctx, []*types.Chunk{chunk}); err != nil {
		return nil, fmt.Errorf("failed to create chunk: %w", err)
	}

	// 索引chunk:交互式创建给索引步骤设硬上限,避免 embedding 抖动把请求拖长
	indexCtx, cancelIndex := context.WithTimeout(ctx, faqCreateIndexBudget)
	indexErr := s.indexFAQChunks(indexCtx, kb, faqKnowledge, []*types.Chunk{chunk}, embeddingModel, true, false)
	cancelIndex()
	if indexErr != nil {
		// 如果索引失败,删除已创建的chunk。回滚失败会留下一条 stored 状态的
		// 残留:它不出现在列表里,却会被重复校验命中,因此必须告警而非静默。
		if delErr := s.chunkService.DeleteChunk(ctx, chunk.ID); delErr != nil {
			logger.Errorf(ctx,
				"CreateFAQEntry: rollback failed, chunk %s left in stored state: %v", chunk.ID, delErr)
		}

View on GitHub (pinned to 988cbb0330)