Billionmail/BillionMail · error

error marshalling knowledge base: %v

Error message

error marshalling knowledge base: %v

What it means

SaveKnowledgeBase serializes a KnowledgeInfo struct to indented JSON before writing it to PRODUCT_CONFIG_PATH/<domain>/knowledge/<kid>.json. This error is wrapped when json.MarshalIndent fails. In practice it is nearly impossible to hit with the plain KnowledgeInfo struct since its fields are all JSON-marshalable; it only fires on pathological runtime conditions.

Source

Thrown at core/internal/service/askai/project.go:318

	err = json.Unmarshal(data, &knowledge)
	if err != nil {
		return KnowledgeInfo{}, fmt.Errorf("error unmarshalling knowledge base: %v", err)
	}
	return knowledge, nil
}

// SaveKnowledgeBase saves the provided KnowledgeInfo to a JSON file based on the domain and knowledge ID.
// It creates the directory if it does not exist and writes the knowledge information to a JSON file
func SaveKnowledgeBase(Domain string, knowledge KnowledgeInfo) error {
	knowledgePath := fmt.Sprintf("%s/%s/knowledge", PRODUCT_CONFIG_PATH, Domain)
	if !public.FileExists(knowledgePath) {
		os.MkdirAll(knowledgePath, os.ModePerm)
	}
	filename := fmt.Sprintf("%s/%s.json", knowledgePath, knowledge.Kid)

	configStr, err := json.MarshalIndent(knowledge, "", "  ")
	if err != nil {
		return fmt.Errorf("error marshalling knowledge base: %v", err)
	}

	err = os.WriteFile(filename, configStr, os.ModePerm)
	if err != nil {
		return fmt.Errorf("error writing knowledge base file: %v", err)
	}
	return nil
}

// GetKnowledgeBaseList retrieves a list of all knowledge bases for a given domain.
// It reads the knowledge base directory, iterates through the files, and returns a slice of KnowledgeInfo structs.
// If the directory does not exist or cannot be read, it returns an error.
func GetKnowledgeBaseList(Domain string) ([]KnowledgeInfo, error) {
	knowledgePath := fmt.Sprintf("%s/%s/knowledge", PRODUCT_CONFIG_PATH, Domain)
	if !public.FileExists(knowledgePath) {
		os.MkdirAll(knowledgePath, os.ModePerm)
		// If the knowledge base directory does not exist, create it
	}

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Check the wrapped %v error from json.MarshalIndent for the UnsupportedTypeError path and which field it names
  2. Remove or make JSON-marshalable any recently added field on KnowledgeInfo (tag it json:"-" if it is runtime-only)
  3. If a custom MarshalJSON exists on KnowledgeInfo or its fields, fix it to never return an error for valid states

Example fix

// before
Chunkifies []chan int // new field causes json: unsupported type
// after
Chunkifies []chan int `json:"-"` // exclude runtime-only field from JSON
Defensive patterns

Strategy: validation

Validate before calling

func isJSONMarshalable(v any) error {
    _, err := json.Marshal(v)
    return err
}
// call before SaveKnowledgeBase:
if err := isJSONMarshalable(knowledge); err != nil {
    return fmt.Errorf("knowledge not serializable: %w", err)
}

Type guard

func hasRuntimeOnlyFields(k KnowledgeInfo) bool {
    // ensure runtime-only members are tagged json:"-"
    return true
}

Try / catch

if err := SaveKnowledgeBase(domain, kb); err != nil {
    if strings.Contains(err.Error(), "marshalling") {
        log.Errorf("KnowledgeInfo contains unmarshalable field: %v", err)
    }
}

Prevention

When it happens

Trigger: json.MarshalIndent(knowledge, ...) returns an error — e.g. a field on KnowledgeInfo carries an unsupported type such as a channel, func, or a circular value; or a custom MarshalJSON method on the struct errors.

Common situations: A developer adds a new field of an unsupported type (chan, func, sync.Mutex with marshaling logic) to KnowledgeInfo; a custom MarshalJSON implementation returns an error; generics/any-typed fields holding bad data.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/09efbe4c536e026b. Report an issue: GitHub.