{"record":{"id":"8ab25ac07e23ba1d","repo":"Billionmail/BillionMail","slug":"error-unmarshalling-knowledge-base-v","errorCode":null,"errorMessage":"error unmarshalling knowledge base: %v","messagePattern":"error unmarshalling knowledge base: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/project.go","lineNumber":302,"sourceCode":"\treturn nil\n}\n\n// ReadKnowledgeBase reads a specific knowledge base from a JSON file based on the provided domain and knowledge ID.\n// It returns a KnowledgeInfo struct or an error if the file does not exist or cannot be\nfunc ReadKnowledgeBase(Domain string, Kid string) (KnowledgeInfo, error) {\n\tfilename := fmt.Sprintf(PRODUCT_CONFIG_PATH+\"/%s/knowledge/%s.json\", Domain, Kid)\n\tif !public.FileExists(filename) {\n\t\treturn KnowledgeInfo{}, fmt.Errorf(\"knowledge base file does not exist: %s\", filename)\n\t}\n\tdata, err := os.ReadFile(filename)\n\tif err != nil {\n\t\treturn KnowledgeInfo{}, fmt.Errorf(\"error reading knowledge base file: %v\", err)\n\t}\n\n\tvar knowledge KnowledgeInfo\n\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","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/project.go#L284-L320","documentation":"After a successful read, ReadKnowledgeBase unmarshals the bytes into a KnowledgeInfo struct. Malformed or schema-incompatible JSON yields 'error unmarshalling knowledge base: %v' with the encoding/json cause. The file exists and was readable, but its contents cannot be represented as KnowledgeInfo.","triggerScenarios":"ReadKnowledgeBase(Domain, Kid) where the JSON file exists and reads fine but json.Unmarshal fails: truncated file, invalid syntax, or fields with wrong types (e.g. string where KnowledgeInfo expects a number/array).","commonSituations":"Partial write from a crashed SaveKnowledgeBase (no atomic rename); manual editing that broke JSON syntax; KnowledgeInfo struct fields changed in a code update so old files no longer decode; non-JSON content saved under a .json name.","solutions":["Validate the file with jq (or json.Unmarshal in a scratch test) to see the exact syntax/type error","Compare file contents against the current KnowledgeInfo struct field types","Re-save the knowledge entry (or delete it) via SaveKnowledgeBase to regenerate valid JSON","Make saves atomic (write temp file + os.Rename) to prevent truncation","Inspect the wrapped json error (offset/type mismatch) to locate the bad field"],"exampleFix":"// before\nkb, err := askai.ReadKnowledgeBase(domain, kid)\n// after\nkb, err := askai.ReadKnowledgeBase(domain, kid)\nif err != nil && strings.Contains(err.Error(), \"unmarshalling\") {\n    os.Remove(fmt.Sprintf(PRODUCT_CONFIG_PATH+\"/%s/knowledge/%s.json\", domain, kid))\n    return fmt.Errorf(\"corrupt knowledge %s removed: %w\", kid, err)\n}","handlingStrategy":"validation","validationCode":"data, err := os.ReadFile(fmt.Sprintf(PRODUCT_CONFIG_PATH+\"/%s/knowledge/%s.json\", domain, kid))\nif err != nil { return err }\nvar probe askai.KnowledgeInfo\nif err := json.Unmarshal(data, &probe); err != nil {\n    return fmt.Errorf(\"corrupt knowledge file: %w\", err)\n}","typeGuard":"func validKnowledgeJSON(data []byte) bool {\n    var k askai.KnowledgeInfo\n    return json.Unmarshal(data, &k) == nil\n}","tryCatchPattern":"kb, err := askai.ReadKnowledgeBase(domain, kid)\nif err != nil && strings.Contains(err.Error(), \"unmarshalling knowledge base\") {\n    log.Printf(\"corrupt knowledge %s/%s: %v\", domain, kid, err)\n    return respondConflict(\"knowledge entry is corrupt; re-save it\")\n}","preventionTips":["Always write knowledge files atomically (temp + rename)","Run json.Unmarshal validation after every save","Version the KnowledgeInfo schema and migrate old files","Reject non-JSON uploads regardless of extension","Include the json offset/type error from the wrapped cause in logs"],"tags":["go","json","knowledge-base"],"backgroundTag":"json-unmarshal-failed","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"}