{"record":{"id":"09efbe4c536e026b","repo":"Billionmail/BillionMail","slug":"error-marshalling-knowledge-base-v","errorCode":null,"errorMessage":"error marshalling knowledge base: %v","messagePattern":"error marshalling knowledge base: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/project.go","lineNumber":318,"sourceCode":"\terr = json.Unmarshal(data, &knowledge)\n\tif err != nil {\n\t\treturn KnowledgeInfo{}, fmt.Errorf(\"error unmarshalling knowledge base: %v\", err)\n\t}\n\treturn knowledge, nil\n}\n\n// SaveKnowledgeBase saves the provided KnowledgeInfo to a JSON file based on the domain and knowledge ID.\n// It creates the directory if it does not exist and writes the knowledge information to a JSON file\nfunc SaveKnowledgeBase(Domain string, knowledge KnowledgeInfo) error {\n\tknowledgePath := fmt.Sprintf(\"%s/%s/knowledge\", PRODUCT_CONFIG_PATH, Domain)\n\tif !public.FileExists(knowledgePath) {\n\t\tos.MkdirAll(knowledgePath, os.ModePerm)\n\t}\n\tfilename := fmt.Sprintf(\"%s/%s.json\", knowledgePath, knowledge.Kid)\n\n\tconfigStr, err := json.MarshalIndent(knowledge, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshalling knowledge base: %v\", err)\n\t}\n\n\terr = os.WriteFile(filename, configStr, os.ModePerm)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing knowledge base file: %v\", err)\n\t}\n\treturn nil\n}\n\n// GetKnowledgeBaseList retrieves a list of all knowledge bases for a given domain.\n// It reads the knowledge base directory, iterates through the files, and returns a slice of KnowledgeInfo structs.\n// If the directory does not exist or cannot be read, it returns an error.\nfunc GetKnowledgeBaseList(Domain string) ([]KnowledgeInfo, error) {\n\tknowledgePath := fmt.Sprintf(\"%s/%s/knowledge\", PRODUCT_CONFIG_PATH, Domain)\n\tif !public.FileExists(knowledgePath) {\n\t\tos.MkdirAll(knowledgePath, os.ModePerm)\n\t\t// If the knowledge base directory does not exist, create it\n\t}","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/project.go#L300-L336","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the wrapped %v error from json.MarshalIndent for the UnsupportedTypeError path and which field it names","Remove or make JSON-marshalable any recently added field on KnowledgeInfo (tag it json:\"-\" if it is runtime-only)","If a custom MarshalJSON exists on KnowledgeInfo or its fields, fix it to never return an error for valid states"],"exampleFix":"// before\nChunkifies []chan int // new field causes json: unsupported type\n// after\nChunkifies []chan int `json:\"-\"` // exclude runtime-only field from JSON","handlingStrategy":"validation","validationCode":"func isJSONMarshalable(v any) error {\n    _, err := json.Marshal(v)\n    return err\n}\n// call before SaveKnowledgeBase:\nif err := isJSONMarshalable(knowledge); err != nil {\n    return fmt.Errorf(\"knowledge not serializable: %w\", err)\n}","typeGuard":"func hasRuntimeOnlyFields(k KnowledgeInfo) bool {\n    // ensure runtime-only members are tagged json:\"-\"\n    return true\n}","tryCatchPattern":"if err := SaveKnowledgeBase(domain, kb); err != nil {\n    if strings.Contains(err.Error(), \"marshalling\") {\n        log.Errorf(\"KnowledgeInfo contains unmarshalable field: %v\", err)\n    }\n}","preventionTips":["Tag runtime-only fields (channels, funcs, conns) with json:\"-\"","Keep KnowledgeInfo composed of JSON-safe primitives","Add a unit test marshalling a fully populated KnowledgeInfo","Run go vet / lint to catch new struct fields lacking serialization support"],"tags":["go","json","serialization","filesystem"],"backgroundTag":"json-unsupported-type","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}